10

I'm trying to use xargs to run a command for each provided argument, but unfortunately the --replace/-I flag doesn't seem to work properly when conjugated with -n. It seems that {} will expand into the full list of arguments read from stdin, regardless of the -n option.

Unfortunately all of the examples on the web seem to be for commands (mv, cp, rm) which will take multiple arguments where {} is expanded.

For example, when running:

echo a b c d | xargs -n 1 -I {} echo derp {}

The output is:

derp a b c d

But I expected:

derp a
derp b
derp c
derp d

However, running it without -I {} yields the expected result:

echo a b c d | xargs -n 1 echo derp
derp a
derp b
derp c
derp d

Is there any way to achieve this with xargs? My ultimate intention is to use it to run multiple (parralel) ssh sessions, like

echo server{1..90} | xargs -n 1 -P 0 -I {} ssh {} 'echo $SOME_HOST_INFO'

I'm running xargs (GNU findutils) 4.4.2 on RHEL 6.3.

  • 2
    Interestingly it works as you intend with BSD xargs, but not GNU xargs. – slhck Jul 26 '13 at 9:39
  • 1
    man xargs on -I: Also, unquoted blanks do not terminate input items; instead the separator is the newline character. Implies -x and -L 1. So it behaves as designed. – Daniel Beck Jul 26 '13 at 12:09
  • @André, since your intention is to run taks in parallel, have you taken a look at GNU parallel? It does the job nicely. Disclaimer: I package it for Debian. – rbrito Jul 30 '13 at 12:58
  • GNU parallel seemed like a good replacement, but unfortunately I can't install it on this particular host. – André Fernandes Aug 11 '13 at 15:31
  • @AndréFernandes Can you elaborate if you reason is not covered by oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html – Ole Tange Aug 18 '13 at 11:00
5

You can echo with newlines to achieve your expected result. In your case with the server expansion that would be:

$ echo -e server{1..4}"\n" | xargs -I{} echo derp {}
derp server1
derp server2
derp server3
derp server4
  • The newline idea works around the issue (just not with your exact example): echo server{1..4} | tr ' ' '\n' | xargs -I{} echo derp {} derp server1 derp server2 derp server3 derp server4 – André Fernandes Jul 26 '13 at 12:07
  • Sorry, tested it with zsh ... Fixed my answer. echo needs the -e option. – ahilsend Jul 26 '13 at 12:11
2

You can make use of an extra pipe like this,

echo a b c d | xargs -n1 | xargs -I{} echo derp {}
derp a
derp b
derp c
derp d

The intermediate use of xargs 'echos' each letter 'a b c d' individually because of the '-n1' option. This puts each letter on it's own line like this,

echo a b c d | xargs -n1
a
b
c
d 

It's important to understand when using -I (string replacement), xargs implies -L, which executes the utility command (in your case echo) once per line. Also, you cannot use -n with -L as they are mutually exclusive.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.