11

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.

5
  • 2
    Interestingly it works as you intend with BSD xargs, but not GNU xargs.
    – slhck
    Jul 26, 2013 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, 2013 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, 2013 at 12:58
  • GNU parallel seemed like a good replacement, but unfortunately I can't install it on this particular host. Aug 11, 2013 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, 2013 at 11:00

2 Answers 2

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
2
  • 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 Jul 26, 2013 at 12:07
  • Sorry, tested it with zsh ... Fixed my answer. echo needs the -e option.
    – ahilsend
    Jul 26, 2013 at 12:11
3

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.