Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Piping echo output into xargs

Tags:

bash

xargs

I'm trying to pipe a list of values through xargs. Here's a simple example:

echo "Hello Hola Bonjour" | xargs -I _ echo _ Landon

I would expect this to output the following:

Hello Landon
Hola Landon
Bonjour Landon

Instead, the command outputs this:

Hello Hola Bonjour Landon

What am I missing?

like image 587
LandonSchropp Avatar asked Aug 07 '18 23:08

LandonSchropp


3 Answers

Under -I, man xargs says

unquoted blanks do not terminate input items; instead the separator is the newline character

You can specify a different delimiter (at least in GNU xargs):

printf 'Hello Hola Bonjour' | xargs -d' ' -I _ echo _ Landon

More portably, use \0 as the delimiter and -0 to use it:

printf '%s\0' Hello Hola Bonjour | xargs -0 -I _ echo _ Landon
like image 106
choroba Avatar answered Oct 16 '22 10:10

choroba


The delimiter needs to be changed, and you also have to specify the -L option. So either change the delimiter via -d like the other answer suggested, or pipe to sed and replace space with linefeed

echo "Hello Hola Bonjour" | sed -e 's/ /\n/g' | xargs -L 1 -I _ echo _ Landon

Results in

Hello Landon
Hola Landon
Bonjour Landon

Sometimes changing the delimiters is not enough. xargs will sometimes take all the input arguments and pass it all at once. There is no splitting of the arguments.

e.g.

seq 1 7 | xargs echo

results in

1
2
3
4
5
6
7

being passed to xargs, so the output would be

  1 2 3 4 5 6 7

If you add a -L 1 shown in the xargs man page

-L max-lines Use at most max-lines nonblank input lines per command line. Trailing blanks cause an input line to be logically continued on the next input line. Implies -x.

seq 1 7 | xargs -L 1 echo

then you will see

1
2
3
4
5
6
7

You can also covert it manually to a for loop which lets you setup multi line statements more easily.

# be absolutely sure the values the for loop iterates over is well sanitized to avoid glob expansion of the *.
for i in Hello Hola Bonjour
do
  if [ "$i" = "Hello" ]
  then
    echo "$i Landon, language detected as English!"
  else
    echo "$i Landon, language detected as non English."
  fi
done
like image 45
Michael C. Chen Avatar answered Oct 16 '22 10:10

Michael C. Chen


The -I flag changes the delimiter to newline.

Unquoted blanks do not terminate input items; instead the separator is the newline character.

You can read about it here.

You have to manually specify the delimiter to be a space. Echo also inserts a newline by default, which messes up xargs. Use the -n flag to remove the newline.

Here is the fixed command:

echo -n "Hello Hola Bonjour" | xargs -d' ' -I _ echo _ Landon
like image 37
Raphael Facredyn Avatar answered Oct 16 '22 09:10

Raphael Facredyn