Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying replace string in xargs

Tags:

bash

xargs

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.

like image 987
betabandido Avatar asked May 29 '12 16:05

betabandido


People also ask

How do you pass arguments to xargs?

The -c flag to sh only accepts one argument while xargs is splitting the arguments on whitespace - that's why the double quoting works (one level to make it a single word for the shell, one for xargs).

Does xargs run in parallel?

xargs will run the first two commands in parallel, and then whenever one of them terminates, it will start another one, until the entire job is done. The same idea can be generalized to as many processors as you have handy. It also generalizes to other resources besides processors.

How do I run multiple commands in xargs?

To run multiple commands with xargs , use the -I option. It works by defining a replace-str after the -I option and all occurrences of the replace-str are replaced with the argument passed to xargs.

What can I use instead of xargs?

GNU parallel is an alternative to xargs that is designed to have the same options, but is line-oriented. Thus, using GNU Parallel instead, the above would work as expected.


2 Answers

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 
like image 63
fairidox Avatar answered Sep 19 '22 13:09

fairidox


It is possible to do this in one pass (tested in GNU) avoiding the use of the temporary variable assignments

find . -name "*.txt" | xargs -I{} sh -c 'mv "$1" "foo/$(basename ${1%.*}).new.${1##*.}"' -- {} 
like image 33
Santrix Avatar answered Sep 18 '22 13:09

Santrix