8

I'm using xargs to populate the arguments to a script in which I want to stop the script, waiting for user input. Something like:

echo a b c | xargs bash -c 'for a in "$@"; do echo $a; read; done'

but the read gets ignored. It seems that the second script is trying to get it's input from the pipe too? I've tried xargs -p but it's no better.

drevicko
  • 14,382
  • 15
  • 75
  • 97

2 Answers2

7

If the option -a is given to xargs, the arguments will be read from a file instead of stdin. You can use bash's process substitution with the syntax <( ... ) to create the file on the fly.

xargs -a <( echo A B C ) bash -c 'for x in "$@"; do echo $x; read; done'

Note that here$@misses the first argument ('A' in this case). This is because bash -c puts 'A' into $0 (which normally takes the name of the script file), and $@ provides $1, $2 etc... (in this case 'B' and 'C').

drevicko
  • 14,382
  • 15
  • 75
  • 97
nosid
  • 48,932
  • 13
  • 112
  • 139
  • wonderful! Thanks (: An interesting note: "$@" here catches 'b' then 'c'. 'a' is stored in $0, 'b' in $1 etc.. – drevicko Apr 19 '12 at 13:14
2

Another solution, which doesn't rely on Bash but on GNU's flavor of xargs, is to use the -o or --open-tty option:

echo a b c | xargs --open-tty bash -c 'for a in "$@"; do echo $a; read; done'

From the manpage:

-o, --open-tty
       Reopen  stdin as /dev/tty in the child process before executing the command.  This is use‐
       ful if you want xargs to run an interactive application.
Riyyi
  • 98
  • 5