20

From my understanding, the following should mean exactly the same:

ls -1 | xargs file {}
ls -1 | xargs -I{} file {}

if -I option is not specified, it is default to -I{}.

I want to list all files in the current directory and run file command on each of them. Some have spaces in their names. However, I noticed the difference. See below:

$ ls -1
Hello World
$ ls -1 | xargs file {}
{}:    ERROR: cannot open `{}' (No such file or directory)
Hello: ERROR: cannot open `Hello' (No such file or directory)
World: ERROR: cannot open `World' (No such file or directory)
$ ls -1 | xargs -I{} file {}
Hello World: directory

With -I{} explicitly specified, blanks in file names are treated as expected.

7
  • 4
    "if -I option is not specified, it is default to -I{}" -- this is incorrect, at least with GNU xargs.
    – jjlin
    Oct 7, 2013 at 1:18
  • 1
    I understand my mistake. I should specify either xargs file or xargs -I{} file {}. Shouldn't be xargs file {}. I guess when explicitly specifying -I{}, the bash will treat it as file "Hello World". Without -I{}, it is treated as file Hello World. Oct 7, 2013 at 4:01
  • 1
    (1) This discussion has little to do with the shell (bash). (2) It’s good that you know the -1 option to ls, but it’s on by default when the output of ls is a file or a pipe, so you don’t need it here. (3) You’re confusing -I with the deprecated -i (lower case I) option. -ifoo is equivalent to -Ifoo, but plain -i is equivalent to -I{}. But use -I{}. (4) If you really want to do what you say you want to do, why not just say file *? Oct 8, 2013 at 0:36
  • @Scott My original intent was to write ` find . -name "*.mov" | xargs -I{} file {}` to find all mov files recursively and run file on them. But I came up with a simpler example using ls. You are right. For that, file * is the best. Oct 8, 2013 at 2:23
  • 1
    find has -exec. Oct 22, 2013 at 11:03

1 Answer 1

27

The -I requires a defined placeholder. The -i option will assume {} is the placeholder. This was where I found any assumption of {} in man xargs at least on Cygwin and CentOS.

xargs called without either option does not need the placeholder and it just appends the STDIN to the end of the arguments.

Just add echo to your examples to see what xargs is doing:

$ ls -1
Hello World/

Your example mistakenly uses {}:

$ ls -1 | xargs echo file {}
file {} Hello World/

so the file cmd sees args of {} Hello World and errors.

If you want to explicitly use {} in your xargs call:

$ ls -1 | xargs -I{} echo file {}
file Hello World/

Or with No placeholder:

$ ls -1 | xargs echo file
file Hello World/

xargs as called above does not need the {}. It appends the STDIN to the end of the command without a placeholder. The use of {} usually means you want the STDIN somewhere in the middle of the cmd to execute, as in:

$ ls -1 | xargs -i mv {} /path/to/someplace/.
2
  • That is very clear. Even though your answer is a bit late, but reading it really reinforces my understanding. Nov 10, 2013 at 5:03
  • According to the man page, the -i argument is deprecated and shouldn't be used. Jul 9, 2020 at 20:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .