简体   繁体   中英

Renaming files in folder and subfolders using a list- Bash Script/Unix

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:

  1. list the files with their paths
  2. extract the basename (but keep a link to the path info)
  3. match the basenames with your replace.txt file to get the new names
  4. recreate the new full paths
  5. and then do the 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM