Search code examples
bashfindrenaming

How do I rename files found with the find command


I have a series of music folders. Some of the file names contain an underscore which I would like to get rid of.

With

find /Users/Chris/CDs -type f -name "*_*" 

I find all of the files with underscores. it appears that I can add -execdir mv {} to the command but do not know what to add from there. I think {} provides the full path and file name as a string of the file with underscores but I do not know how to use something like sed 's/_//g' to remove the _ on the new file name. Any help would be greatly appreciated.


Solution

  • Try:

    find /Users/Chris/CDs -type f -name "*_*" -execdir bash -c 'mv -i -- "$1" "${1//_/}"' Mover  {} \;
    

    How it works:

    • -execdir bash -c '...' Mover {} \;

      This starts up bash and tells it to run the command in the single quotes with Mover assigned to $0 and the file name assigned to $1.

    • mv -i -- "$1" "${1//_/}"

      This renames file $1. This uses bash's parameter expansion feature, ${1//_/}, to create the target name from $1 by removing all underlines.

      The option -i tells mv to ask interactively before overwriting a file.

      The option -- tells mv that there are no more options. This is needed so that files whose names begin with - will be processed correctly.

    Example

    Let's start with a directory with these files:

    $ ls
    1_2_3_4  a_b  c_d
    

    Next we run our command:

    $ find . -type f -name "*_*" -execdir bash -c 'mv -i -- "$1" "${1//_}"' Mover  {} \;
    

    After the command completes, the files are:

    $ ls
    1234  ab  cd
    

    The purpose of $0

    Observe this command where we have added an error:

    $ find . -type f -name "*_*" -execdir bash -c 'foobar -i -- "$1" "${1//_}"' Mover  {} \;
    Mover: foobar: command not found
    

    Note that Mover appears at the beginning of the error message. This signals that the error comes from within the bash -c command.

    If we replace Mover with -, we would see:

    $ find . -type f -name "*_*" -execdir bash -c 'foobar -i -- "$1" "${1//_}"' -  {} \;
    -: foobar: command not found
    

    When running a single command in a terminal, the source of the error may still be obvious anyway. If this find command were buried inside a long script, however, the use of a more descriptive $0, like Mover or whatever, could be a big help.