3

Input 0

echo foo | xargs -L 1 -I '{}' echo '{}'

Output 0

foo

Input 1

echo foo | xargs -I '{}' -L 1 echo '{}'

Output 1

{} foo

Why changing the order of options of xargs changes the output?

Version: xargs (GNU findutils) 4.6.0

  • Also cannot replicate this on the Mac BSD... – Alex Aug 23 '17 at 23:04
5

When options given to xargs conflict, order may matter.

IEEE Std 1003.1-2008, 2016 Edition/Open Group Base Specifications Issue 7 added the following text1 to the specification of xargs:

The -I, -L, and -n options are mutually-exclusive. Some implementations use the last one specified if more than one is given on a command line; other implementations treat combinations of the options in different ways.

This codifies the behavior of many implementations of xargs, going back to the original version in PWB/Unix, whose man page says

When there are flag conflicts (e.g., -l vs. -n), the last flag has precedence.

In the GNU version of xargs, -L disables any previous -I option. So in your second example,

echo foo | xargs -I '{}' -L 1 echo '{}'

{} is just an ordinary argument passed to echo, with no substitution being done.

[1]Compared to IEEE Std 1003.1, 2004 Edition/Open Group Base Specifications Issue 6.

  • You are awesome. Let's have a further discussion then. I don't really understand why -I has to conflict against -n. It seems -I is the only way of putting the argument in the middle of the command (instead of appending it at the last). But what if the user wants at most 1 argument for each command (-n 1) at the same time? Then he has to write -I {} -n 1 or -n 1 -I {} but both are invalid. Why xargs has to have this limitation? – Cyker Aug 24 '17 at 5:23
  • @Cyker, -I changes the way the input is read (one arg per line with leading but not trailing blanks removed, and quoting still understood) and uses one arg at a time anyway so -n 1 would be redundant. -I with GNU xargs works in combination with -d or -0 which is all what matters there. Compare printf ' a b\nc d \n' | xargs -n1 sh -c 'IFS=,; printf "<%s>\n" "$*"' sh {} with the same with -L1 instead of -n1 and with -I {} and with -d '\n' -I {} – Stéphane Chazelas Aug 24 '17 at 11:11
  • xargs -I {} cmd {} is not the same as xargs -L1 cmd. In the latter case, the words on each line make up separate arguments to cmd. – Stéphane Chazelas Aug 24 '17 at 11:15
  • @StéphaneChazelas Yeah, I mentioned the -I implies -L 1 bit because it says so on the GNU man page, but now I see that it's wrong. I'll remove my comment and reword it. – Mark Plotnick Aug 24 '17 at 11:41
  • 1
    @Cyker Going back to the original version of xargs 40 years ago, if you gave it -i, it used complete lines as input and ignored any -n option. I don't know why they chose to do this, but I'd guess the major use case for xargs -i was to process lists of filenames, one per line, such as the output of find. Nowadays, you could use the shell for command and shell variables to loop over files, using either the output of find $(find ...) or globs. The PWB/Unix shell did not have a for command. – Mark Plotnick Aug 24 '17 at 15:17

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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