Shell script copy file from one dir to another - bash

I am trying to copy a file from a dir to another directory location using regx * like below
cp /location1/abc_* /location/xyz_
Its failing to copy because In location1 there are many files with abc_123 abc_234 like these.
Seems like command get confuse to copy which file as xyz_
I want to copy only the file which is recent abc_ file. Is there any way to achieve this requirement?

You can iterate over the glob to select the most recent file, then copy that one file. (Every file compares as "newer" than a non-existent file
newest=
for f in /location1/abc_*; do
[[ $f -nt $newest ]] && newest=$f
done
cp "$newest" /location/xyz_/

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.

Unable to rename and move files from one location to another

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.

Renaming multiples files from differernt directories using shell script

I have 50 directories and inside each directory I have a file of the name hist_anh_abs_0. So I have 50 files of the
name hist_anh_abs_0
What I want is the following, I want to run a loop over all 50 directories and which will pull out the file name hist_anh_abs_0 and rename it like hist_anh_abs_0_1, hist_anh_abs_0_2... and finally put all the renamed files in a separate directory.
I did something like this
for file in hist_anh_abs_0
do
mv -i "${file}" "${file/-_abs_0-/-_abs_0_$i-}"
done
But I can't do the part where it will read all the directories and look for the file of name hist_anh_abs_0
ct=0 ;
for f in */hist_anh_abs_0
do
mv $f ${destdir}/${f}_$((ct++));
done

Move files to the correct folder in Bash

I have a few files with the format ReportsBackup-20140309-04-00 and I would like to send the files with same pattern to the files as the example to the 201403 file.
I can already create the files based on the filename; I would just like to move the files based on the name to their correct folder.
I use this to create the directories
old="directory where are the files" &&
year_month=`ls ${old} | cut -c 15-20`&&
for i in ${year_month}; do
if [ ! -d ${old}/$i ]
then
mkdir ${old}/$i
fi
done
you can use find
find /path/to/files -name "*201403*" -exec mv {} /path/to/destination/ \;
Here’s how I’d do it. It’s a little verbose, but hopefully it’s clear what the program is doing:
#!/bin/bash
SRCDIR=~/tmp
DSTDIR=~/backups
for bkfile in $SRCDIR/ReportsBackup*; do
# Get just the filename, and read the year/month variable
filename=$(basename $bkfile)
yearmonth=${filename:14:6}
# Create the folder for storing this year/month combination. The '-p' flag
# means that:
# 1) We create $DSTDIR if it doesn't already exist (this flag actually
# creates all intermediate directories).
# 2) If the folder already exists, continue silently.
mkdir -p $DSTDIR/$yearmonth
# Then we move the report backup to the directory. The '.' at the end of the
# mv command means that we keep the original filename
mv $bkfile $DSTDIR/$yearmonth/.
done
A few changes I’ve made to your original script:
I’m not trying to parse the output of ls. This is generally not a good idea. Parsing ls will make it difficult to get the individual files, which you need for copying them to their new directory.
I’ve simplified your if ... mkdir line: the -p flag is useful for “create this folder if it doesn’t exist, or carry on”.
I’ve slightly changed the slicing command which gets the year/month string from the filename.

Find and copy, rename files with same name

I have this find
find "$source_folder" -name "IMG_[0-9][0-9][0-9][0-9].JPG" -exec cp {} $destination_folder \;
i want only the IMG_[0-9][0-9][0-9][0-9].JPG, in the source folder there are diferent files with same name,and same files with same name, how can i copy everything and rename all the same name files with extra .JPG without deleting any unique files?
PS: noob, please could you explain so i can try and learn
I'll assume that your file names don't contain any whitespace. It makes things easier.
You can pipe the output of the find command to a loop where you can run some tests whether or not you want to copy the file.
I have to determine the name of the file and where it is copied to. In order to do that, I have to strip off the $source_folder from the name of the file I find, and prepend the name of the $dest_folder. This is where I want to actually copy the file.
Your directions are a bit confusing. I am assuming you're doing the copy if the $dest_file doesn't exist or it is different from the source. Once I determine that this is the file you want me to copy, I have to make sure the destination directory exists, and if it doesn't I create it. Now, I can do my copy.
I have two echo statements in here. This way, you can do a dry run of this script to make sure it's doing what you want it to do. If it looks good, you can remove the echo commands from the two lines and rerun the script.
find "$source_folder" -name "IMG_[0-9][0-9][0-9][0-9].JPG" | while read file_name
do
rootname=${file_name#$source_folder/} # Removes the source folder from the name
dest_name="${dest_folder}/$rootname"
if [ ! -e "$dest_name" ] || [ ! diff "$file_name" "$dest_name" > /dev/null 2>&1 ]
then
$dest_folder=$(basename $dest_name)
[ ! -d "$dest_folder" ] && echo mkdir -p "$dest_folder" #Remove echo if it works
echo cp "$file_name" "$dest_name" #Remove 'echo' if it works
fi
done

Resources