Modifying replace string in xargs

betabandido picture betabandido · May 29, 2012 · Viewed 59.7k times · Source

When I am using xargs sometimes I do not need to explicitly use the replacing string:

find . -name "*.txt" | xargs rm -rf

In other cases, I want to specify the replacing string in order to do things like:

find . -name "*.txt" | xargs -I '{}' mv '{}' /foo/'{}'.bar

The previous command would move all the text files under the current directory into /foo and it will append the extension bar to all the files.

If instead of appending some text to the replace string, I wanted to modify that string such that I could insert some text between the name and extension of the files, how could I do that? For instance, let's say I want to do the same as in the previous example, but the files should be renamed/moved from <name>.txt to /foo/<name>.bar.txt (instead of /foo/<name>.txt.bar).

UPDATE: I manage to find a solution:

find . -name "*.txt" | xargs -I{} \
    sh -c 'base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; \
           mv "$1" "foo/${name}.bar.${ext}"' -- {}

But I wonder if there is a shorter/better solution.

Answer

fairidox picture fairidox · Feb 21, 2014

The following command constructs the move command with xargs, replaces the second occurrence of '.' with '.bar.', then executes the commands with bash, working on mac OSX.

ls *.txt | xargs -I {} echo mv {} foo/{} | sed 's/\./.bar./2' | bash