Search code examples
bashsedawkxargs

Using backticks or $() with xargs and sed or awk


Assuming I want to change some filenames that end with jpg.jpg to end only with .jpg (in bash), and I want to do it by piping the output of find to xargs:

By using sed:

find . -iname '*jpg.jpg' | xargs -I % mv -iv % $(echo % | sed 's/jpg.jpg/.jpg/g')

However, this does not replace jpg.jpg with .jpg in the destination file of mv.

By using awk:

find . -iname '*jpg.jpg' | xargs -I % mv -iv % $(echo % | awk '{gsub(/jpg.jpg/,".jpg")}; 1')

This neither does any replacement. Have I missed something?


Solution

  • I would do this by writing a script that takes filenames and does the rename:

    #!/bin/sh
    
    for FILE
    do
        mv $FILE `basename $FILE jpg.jpg`.jpg
    done
    

    That script is easily called via xargs.

    If you want to smash it onto a single command line you can do it but it's usually not worth the trouble.

    EDIT: If I had to do it on one command line I'd probably use a different trick without xargs: Use sed to turn the output of find into a shell script:

    find . -iname '*jpg.jpg' | sed -e 's/\(.*\)jpg\.jpg$/mv & \1.jpg/' | sh
    

    The advantage of xargs being able to fork off fewer children is defeated by the need to run mv repeatedly anyway. If you really need that advantage you need a solution like my first option but coded in something like perl which can execute multiple rename() calls without forking off any mv.