Unable to rename and move files from one location to another - shell

I need to add prefix C_ and then move files from tmp location to target location.
Here is the script
I am not allowed to place script in current directory.
for tmpfile in /home/asmita/tmp
do
mv "$tmpfile" "C_${tmpfile}"
mv "C_${tmpfile}" /home/tgasmita
done
When I try moving prefixed files I get error C_/home/asmita/tmp/xyz.txt not found. as entire path is stored in tmpfile variable.

Change your code to use the basename and the dirname command to get the filename and the directory name. Use these to combine the values and get the new path.
for tmpfile in /home/asmita/tmp
do
DIRPATH=$(dirname "${tmpfile}")
FILENAME=$(basename "${tmpfile}")
mv "$tmpfile" "${DIRPATH}C_${FILENAME}"
mv "${DIRPATH}C_${FILENAME}" /home/tgasmita
done

There are many ways to do this. First let me fix your script.
1.In below code make sure that you are passing only filename not the full path. Below script is valid only if know the FILENAME
#!/bin/sh
for tmpfile in /home/asmita/tmp
do
mv "{tmpfile}/filename.txt" "/home/tgasmita/C_filename.txt"
done
2.If you do not know file name and you want to rename and move .txt files to another folder then you might like below script.
#!/bin/sh
lines=`find /home/asmita/tmp -name "*.txt" -printf "%f\n";`
for i in ${lines[#]}
do
mv "/home/asmita/tmp/${i}" "/home/tgasmita/C_${i}"
done
Please note that I m looking for only text file in source folder(/home/asmita/tmp
) You can change .txt to other extension according to requirement. If you want to move and rename all files from source folder then just replace "*.txt" to ".*" from second line.

Related

Deleting specific files in a directory using bash

I have a txt file with a list of files (approximately 500) for example:
file_0_hard.msOut
file_1_hard.msOut
file_10_hard.msOut
.
.
.
file_1000_hard.msOut
I want to delete all those files whose name is not in the txt file. All of these files are in the same directory. How can I do this using bash where I read the text file and then delete all those files in the directory that are not in the text file. Help would be appreciated.
Along the lines of user1934428
There is something to say for this solution. But since we have linux at our disposal with a strong filesystem in use I hope. we can make hardlinks; The only requirement for that the destination is on the same filesystem.
So along those lines:
make a directory to store the files you want to keep.
hardlink (ln {file} {target}) ; as this does not cost extra disk space, it only stores the inode number in the new directory file.
remove all files
move the files back from their origin.
And actually this would be about the same as:
mv {files} {save spot}
remove all files
mv {save spot}/{files} back
Which does pretty much the same thing. Then again; it is a nice way to learn about the power of a hardlink.
you may try this :
cd path/dir
for f in *; do
if ! grep -Fxq "$f" pathToFile/file.txt; then
rm -r "$f"
else
printf "exists-- %s \n" ${f}
fi
done
In case you are wondering (as I did) what -Fxq means in plain English:
F: Affects how PATTERN is interpreted (fixed string instead of a regex)
x: Match whole line
q: Shhhhh... minimal printing
Assuming the directory in question is mydir
set -e
cd mydir
tmpdir=/tmp/x$$ # adapt this to your taste
mv $(<list.txt) $tmpdir
cd ..
rm -r mydir
mkdir mydir
mv $tmpdir/* mydir
rm -r $tmpdir
Basically, instead to delete those files you want to keep, you safe them, then delete everything, and then restore them. For your case, this is probably faster than doing the other way around.
UPDATE:
As Michiel commented, it is advisable that you place your tmpdir in the same file system as mydir.

Move files and prepend filename

I am having difficulty moving files and prepending to the files with Bash.
#!/bin/bash
CAT="WFS_CAT"
for FILENAME in /foo/bar/20*
do
mv "${FILENAME##*/}" "${CAT}.${FILENAME##*/}"
done;
The command errors out. It tries to move the full directory name and prepend to that instead of the individual files.
In this case, it should be much simpler to change the directory to the one your files are located in, as your move command only renames files in this directory. Do you mind trying this?
pushd /foo/bar
for FILENAME in 20*; do
echo mv "${FILENAME}" "${CAT}.${FILENAME}"
done;
popd

batch renaming of multiple files of same extension

I need to rename multiple files without knowing the filename(basename/string name ) of the file.
i tried with:
for i in $(ls /Users/Destiny/Desktop/Index/*.ebwt);
do
mv -v "$i" "${i/hsa/hsa.genome.V86C}"; ## works when i know the string to replace
done
but what if dont know the filename(string name)?
Before rename: hsa.1.ebwt hsa.2.ebwt hsa.3.ebwt hsa.4.ebwt
After rename: hsa.genome.V86C.1.ebwt hsa.genome.V86C.2.ebwt hsa.genome.V86C.3.ebwt hsa.genome.V86C.4.ebwt
You could do something with a find in your directory. And if they all have the same extension then it could be something like below with your move that you currently have:
find /Users/Destiny/Desktop/Index -type f -name "*.ebwt" | while read file;
do
mv -v "$file" "${file/hsa/hsa.genome.V86C}";
done
This will rename it inside of the current directory, and if you want to move it to a different directory later down the line, you could surround second argument like this with basename to make moving easier:
"/SomeDirectory/$(basename ${file/hsa/hsa.genome.V86C})"
You could also put a -maxdepth 1 after the directory you want to find if you dont want it to be recursive in the find

Bash. Using find and a for loop. Can't find how to mv file into the directory that was found. Just moves to root directory given.

Current code.
Right now I have a test format set up. Here is what I have.
files=`find C:/PATH/TO/DIRECTORY/2014-05-08 -name *.txt`
(I will be running this from C:/PATH/TO/DIRECTORY. Just right now I'm only testing on todays directory so I don't change everything in /DIRECTORY.) The .sh script is being run from /DIRECTORY therefore it is it's root.) In the implemented version find will look like this:
files=`find C:/PATH/TO/DIRECTORY -name *.txt`
for file in $files; do
#code to manipulate filename
mv $file $newFilename
The problem that I am getting is that this renames the old file name into the new file name, but the new files are in /DIRECTORY when I want them to be in the directory that the program is currently looping through. Which in this case is /DIRECTORY/2014-05-08.
I was just going to make a variable for the current directory of $file, but couldn't figure out how and use:
mv $file /CWD/$newFilename
but I was unable to find a way to assign CWD the directory that $file was in. This would probably be the easiest way if it's possible.
This would be a better way to code that:
find dir -name \*.txt |
while IFS= read -r file; do
dir=$(dirname "$file")
file=$(basename "$file")
newfile=...whatever...
mv "$dir/$file" "$dir/$newfile"
done
Using a for loop over the results of find will iterate over the words in the result, not necessarily the lines -- if there's a filename with a space in it, the for loop won't get the right filename.
The while IFS= read -r line technique I demonstrate is the safest way to iterate over the lines of the result of a command.
There are other issues in my code that I don't think are strictly relevant here.

bash script for copying files between directories

I am writing the following script to copy *.nzb files to a folder to queue them for Download.
I wrote the following script
#!/bin/bash
#This script copies NZB files from Downloads folder to HellaNZB queue folder.
${DOWN}="/home/user/Downloads/"
${QUEUE}="/home/user/.hellanzb/nzb/daemon.queue/"
for a in $(find ${DOWN} -name *.nzb)
do
cp ${a} ${QUEUE}
rm *.nzb
done
it gives me the following error saying:
HellaNZB.sh: line 5: =/home/user/Downloads/: No such file or directory
HellaNZB.sh: line 6: =/home/user/.hellanzb/nzb/daemon.queue/: No such file or directory
Thing is that those directories exsist, I do have right to access them.
Any help would be nice.
Please and thank you.
Variable names on the left side of an assignment should be bare.
foo="something"
echo "$foo"
Here are some more improvements to your script:
#!/bin/bash
#This script copies NZB files from Downloads folder to HellaNZB queue folder.
down="/home/myusuf3/Downloads/"
queue="/home/myusuf3/.hellanzb/nzb/daemon.queue/"
find "${down}" -name "*.nzb" | while read -r file
do
mv "${file}" "${queue}"
done
Using while instead of for and quoting variables that contain filenames protects against filenames that contain spaces from being interpreted as more than one filename. Removing the rm keeps it from repeatedly producing errors and failing to copy any but the first file. The file glob for -name needs to be quoted. Habitually using lowercase variable names reduces the chances of name collisions with shell variables.
If all your files are in one directory (and not in multiple subdirectories) your whole script could be reduced to the following, by the way:
mv /home/myusuf3/Downloads/*.nzb /home/myusuf3/.hellanzb/nzb/daemon.queue/
If you do have files in multiple subdirectories:
find /home/myusuf3/Downloads/ -name "*.nzb" -exec mv {} /home/myusuf3/.hellanzb/nzb/daemon.queue/ +
As you can see, there's no need for a loop.
The correct syntax is:
DOWN="/home/myusuf3/Downloads/"
QUEUE="/home/myusuf3/.hellanzb/nzb/daemon.queue/"
for a in $(find ${DOWN} -name *.nzb)
# escape the * or it will be expanded in the current directory
# let's just hope no file has blanks in its name
do
cp ${a} ${QUEUE} # ok, although I'd normally add a -p
rm *.nzb # again, this is expanded in the current directory
# when you fix that, it will remove ${a}s before they are copied
done
Why don't you just use rm $(a}?
Why use a combination of cp and rm anyway, instead of mv?
Do you realize all files will end up in the same directory, and files with the same name from different directories will overwrite each other?
What if the cp fails? You'll lose your file.

Resources