Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make xargs append trailing arguments with -n?

Tags:

xargs

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
like image 463
Don Hatch Avatar asked Nov 30 '17 14:11

Don Hatch


People also ask

How do you pass arguments to xargs?

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.

What can I use instead of xargs?

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.

Does xargs execute 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.

What does piping to xargs do?

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.


1 Answers

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 by bash -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 of bash, 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
like image 54
Don Hatch Avatar answered Sep 23 '22 15:09

Don Hatch