Bash rename 360 000 files using find -exec

8,239

Solution 1

find  | prename 's/\.jpg$/.jpeg/'

or if you have oder files in the currunt directory

find 0[0-9][0-9] | prename 's/\.jpg$/.jpeg/'

Solution 2

In the first instance, * is expanded by the shell before it gets to rename (if it is expanded at all - I doubt anything matches {}/*), and if it isn't expanded, the command that is executed is rename with the three arguments -n, s/jpg/jpeg/ and some/path/*. That last argument is not the name of an existing file so rename does nothing.

Without shell globbing, the path is useless to rename.

So, instead, do:

find -maxdepth 3 -mindepth 3 -type f -iname '*.jpg' -exec rename -n 's/jpg$/jpeg/i' {} +

Use find's ability to build command lines as long as is possible with + instead of ;.

Solution 3

You should not specify type d unless you want to rename only directories. To change extensions .jpg to .jpeg try

find . -maxdepth 2 -mindepth 2 -name '*.jpg' -exec sh -c 'echo mv -- "$0" "${0%%.jpg}.jpeg"' {} \;

Remove echo if you like what you see on the screen.

Solution 4

Here is an alternative way should rename happen to be missing:

find 0[0-6][0-9] -name "*.jpg" -exec sh -c 'for i do echo mv "$i" "${i%g}eg"; done' sh {} + 
Share:
8,239

Related videos on Youtube

koubic
Author by

koubic

Web developer, PM.

Updated on September 18, 2022

Comments

  • koubic
    koubic almost 2 years

    I've got around 360 000 files like:

    ./001/1/1.jpg
    ./001/1/2.jpg
    ./001/2/1.jpg
    ./002/1/1.jpg
    ./003/1/1.jpg
    ...
    pattern: [60 dirs]/[1000 subdirs]/[4-10 files].jpg
    

    I want to rename files using rename for example from *.jpg to *.jpeg. I can't do it with single rename, because I get the error argument list is too long.

    Searching for solution, I figured out this, but it renames nothing:

    find -maxdepth 2 -mindepth 2 -type d -exec rename -n 's/jpg/jpeg/' {}/* \;

    When I check if the {} is expanded replacing rename with echo:

    find -maxdepth 2 -mindepth 2 -type d -exec echo "rename -n 's/jpg/jpeg/' {}/*" \;

    I get expected result:

    rename -n 's/jpg/jpeg/' ./061/61430/*
    rename -n 's/jpg/jpeg/' ./061/61431/*
    ...
    

    If I run any of these rename commands, I rename works. So the should be problem with the {}.

    Thank you for help!

  • koubic
    koubic over 9 years
    It doesn't really work but it made me remaking the script so now the problem is solved. Thank you.
  • JJoao
    JJoao over 9 years
    @koubic, successfully remaking your own script is even better than a working suggested solution! What is the problem of this version?
  • koubic
    koubic over 9 years
    Ok, I'm sorry, it actually works. It's just a different approach to my original question. Your approach is slower, because rename process has to be run for every single file. My approach wanted to put a subdirectory to rename so rename would be executed severalfold less often. But I eventually used it because speed wasn't a problem on the real server.
  • JJoao
    JJoao over 9 years
    @koubic, thank you for everything. In my approach, rename process should be executed only once. If you can, it would be interesting to "time" the solutions (I'm curious about the time taken for renaming such a big number of files!)
  • Alessio
    Alessio over 6 years
    This, unfortunately, won't work correctly if any of the filenames contain a newline. A workaround is to use -print0 with find for NUL-separated output and run prename (with full path specified) using perl -0 - e.g. find -print0 | perl -0 /usr/bin/prename 's/\.jpg$/.jpeg/'. prename itself should (but doesn't) have a -0 option...I've reported this as a bug to rt-cpan.org.
  • Jonas Eberle
    Jonas Eberle almost 4 years
    This answer is amazing on so many levels. It includes a "testing" mode and it uses primitive commands.