xargs is good at inserting initial arguments:
seq 0 10 | xargs -n 3 echo foo
produces this output:
foo 0 1 2
foo 3 4 5
foo 6 7 8
foo 9 10
What about when I also want trailing arguments? That is, what command:
seq 0 10 | xargs -n 3 <WHAT GOES HERE?>
will produce the following desired output:
foo 0 1 2 bar
foo 3 4 5 bar
foo 6 7 8 bar
foo 9 10 bar
I tried the following:
seq 0 10 | xargs -n 3 -I {} echo foo {} bar
which is almost right, except that it apparently forces 1 item per command line, which isn't what I want:
foo 0 bar
foo 1 bar
foo 2 bar
foo 3 bar
foo 4 bar
foo 5 bar
foo 6 bar
foo 7 bar
foo 8 bar
foo 9 bar
foo 10 bar
The -n ( --max-args ) option specifies the number of arguments to be passed to the given command. xargs runs the specified command as many times as necessary until all arguments are exhausted. In the following example, the number of arguments that are read from the standard input is limited to 1.
If you can't use xargs because of whitespace issues, use -exec . Loops are just as inefficient as the -exec parameter since they execute once for each and every file, but have the whitespace issues that xargs have.
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.
Combine xargs with find The list of files is then piped to xargs , which uses the rm command to delete them. rm now deletes all the files with the . sh extension.
After figuring this out with a head-start from @netniV's answer, I now see that the man page actually contains an example showing how to do it:
xargs sh -c 'emacs "$@" < /dev/tty' emacs
Launches the minimum number of copies of Emacs needed, one after the other, to edit the files listed on xargs' standard input. This example achieves the same effect as BSD's -o option, but in a more flexible and portable way.
And the wikipedia page shows a similar technique, with an explanation of the dummy arg at the end:
Another way to achieve a similar effect is to use a shell as the launched command, and deal with the complexity in that shell, for example:
$ mkdir ~/backups $ find /path -type f -name '*~' -print0 | xargs -0 bash -c 'for filename; do cp -a "$filename" ~/backups; done' bash
The word
bash
at the end of the line is interpreted bybash -c
as special parameter$0
. If the word bash weren't present, the name of the first matched file would be assigned to$0
and the file wouldn't be copied to~/backups
. Any word can be used instead ofbash
, but since$0
usually expands to the name of the shell or shell script being executed,bash
is a good choice.
So, here's how to do it:
seq 0 10 | xargs -n 3 sh -c 'echo foo "$@" bar' some_dummy_string
The output is as desired:
foo 0 1 2 bar
foo 3 4 5 bar
foo 6 7 8 bar
foo 9 10 bar
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With