I'm trying to rename files contained within folders & sub folders. I've many sub folders under each folder which contains various files, so my aim is to run a script at top level folder which hopefully will scan through entire array of sub folders and rename the old file names to new file names given in a separate text file.
For example:
Abc075.tif----------Xyz.tif
def958.pdf----------pqr.pdf
I've this bash script that works on folder level that is if I copy this into each folder (and sub folder) and then run from there.
#!/bin/bash
while read -r old new
do
arr=( ${old} )
if (( ${#arr[@]} == 1 ))
then
mv "${arr[0]}" "$new"
else
echo "Error: Multiple files found for $old: ${arr[@]}"
fi
done < replace.txt
Sorry my knowledge is limited but I've tried to modify this to;
#!/bin/bash
find -type f -iname '*.*' -print0 | while read -r old new
do
arr=( ${old} )
if (( ${#arr[@]} == 1 ))
then
mv "${arr[0]}" "$new"
else
echo "Error: Multiple files found for $old: ${arr[@]}"
fi
done < replace.txt
This would execute but won't work. I've also tried the first script by using this find command;
find /path -type f -name "*.*" -exec /path_of_script.sh {} +
Many thanks in advance.
To use a batch mv
command you'll need to create a tab separated file that'll add explicitly the directory structure that your replace.txt misses, like so:
full/path/old.stuff<TAB>full/path/new.stuff
In order to achieve this you'll have to:
mv
command. So we'll need a few steps using a big table and tools like find
, basename
and join
(the latter also requires some sorting)
1) Go to the uppermost directory where the changes have to be made and simply start with:
find . > all_paths.ls
Then we get basenames similar to what you have in your replace.txt:
for path in `cat all_paths.ls` ; do basename $path ; done > all_names.ls
We'll also need the dirnames:
for path in `cat all_paths.ls` ; do dirname $path ; done > all_dirs.ls
2) These two will make a useful table (combines the names to match your replace.txt file while still keeping track of the dirs):
paste all_names.ls all_dirs.ls > all_name-dir.tsv
3) NOW we make use of your replace.txt file thanks to the magic of join
:
sort replace.txt > replace.sorted.txt
sort all_name-dir.tsv > all_name-dir.sorted.tsv
# join will work fine because "old basenames" are in the first column of both tables
join -t "<TAB>" all_name-dir.sorted.tsv replace.sorted.txt > todo_name-dir-newname.tsv
<TAB>
stands here for the real tab character (you can enter it in shell with CTRL+V then TAB key)
The result should have three columns with content like:
old.stuff<TAB>full/path/<TAB>new.stuff
4) To be able to use all this with the move command, we'll just need to reshape this slightly and glue the paths back together (put some "/" back)
# get the columns back
cut -f2 < todo_name-dir-newname.tsv > todo_dirs.ls
cut -f1 < todo_name-dir-newname.tsv > todo_oldnames.ls
cut -f3 < todo_name-dir-newname.tsv > todo_newnames.ls
# glue 2 and 1 together for reconstructed old paths
paste todo_dirs.ls todo_oldnames.ls | tr "\t" "/" > todo_oldpaths.ls
# same for the new ones
paste todo_dirs.ls todo_newnames.ls | tr "\t" "/" > todo_newpaths.ls
# and we get the table we wanted
paste todo_oldpaths.ls todo_newpaths.ls > replace_table.tsv
5) Now finally you can proceed with moving:
for line in `cat replace_table.tsv`
do oldpath=`echo $line | cut -f1`
newpath=`echo $line | cut -f2`
mv $oldpath $newpath
done
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.