Search code examples
linuxbashshellbatch-rename

Writing a bash script to rename files sequentially in current directory and sub-directories


How do I fix this script so that it uses the user-input STRING to rename all files in the current directory, and all files in sub-directories?

Current filenames could be anything. I want the ending result for all files to be called STRING_001.jpg STRING_002.jpg STRING_003.jpg etc...

It does NOT matter to me, if the files are only sequential in their respective directories, or if the file number carries over to the next directory.

This is the code I ended up writing, after a few hours of research:

#!/bin/bash

# Let user input a string to use in filenames
read -p "Enter filename: " STRING

# Variable for sequential filenames
n=0

files=(./*)

# Looks for files in current directory
if [ ${#files[@]} -gt 0 ]; 
then
        for f in ./*; do
                  # Renames files with STRING and sequentially
                printf -v num %03d "$((++i))"
                mv "$f" "${STRING}_$num.jpg" 
        done
else 
        for d in *; do
        ( cd -- "$d" && 
                for f in ./*; do 
                          # Executes rename command in sub-directories
                        printf -v num %03d "$((++i))"
                        mv "$f" "${STRING}_$num.jpg" 
                done 
        )
done;
fi

Solution

  • Script:

    #!/bin/bash
    read -p "Enter filename: " STRING
    find . -type f | cat -n - | while read num infile ; do
        filename=$(basename "${infile}")
        filesans="${filename%%.*}"
        newname=$(printf '%s_%03d' "${STRING}" "${num}")
        newfile="${infile/$filesans/$newname}"
        echo "mv \"${infile}\" \"${newfile}\""
    done
    

    (Here, this script is named 62566825.sh. Not the greatest name.)

    Setup the directory:

    mkdir dir1 dir2 dir3
    touch dir1/file{1,2,3} dir2/file{4,5,6}.jpg dir3/file{7,8,9}.foo.gz
    
    $ find . -type f
    ./62566825.sh
    ./dir1/file1
    ./dir1/file2
    ./dir1/file3
    ./dir2/file4.jpg
    ./dir2/file5.jpg
    ./dir2/file6.jpg
    ./dir3/file7.foo.gz
    ./dir3/file8.foo.gz
    ./dir3/file9.foo.gz
    

    Execution:

    $ ./62566825.sh
    Enter filename: QUUX
    mv "./62566825.sh" "./QUUX_001.sh"
    mv "./dir1/file1" "./dir1/QUUX_002"
    mv "./dir1/file2" "./dir1/QUUX_003"
    mv "./dir1/file3" "./dir1/QUUX_004"
    mv "./dir2/file4.jpg" "./dir2/QUUX_005.jpg"
    mv "./dir2/file5.jpg" "./dir2/QUUX_006.jpg"
    mv "./dir2/file6.jpg" "./dir2/QUUX_007.jpg"
    mv "./dir3/file7.foo.gz" "./dir3/QUUX_008.foo.gz"
    mv "./dir3/file8.foo.gz" "./dir3/QUUX_009.foo.gz"
    mv "./dir3/file9.foo.gz" "./dir3/QUUX_010.foo.gz"
    

    (Just fix the echo "mv to actually do something.)