Here is the command in question

 find . -name "*.txt" | xargs -Ifile sh -c 'echo $(basename $1) ' -- file

So without the double dash the file is not passed to sh and then get recognized as $1. Why is that? I know that -- prevents the consequent argument from being recognized as command line options. But since file is not prepended with a dash, it seems as though there is no reason for it to get recognized as a command line option.


The first non-option argument to sh becomes $0. When sh is invoked on a script, that's the path to the script. When you run sh -c SOMECOMMAND, the shell doesn't use the argument for anything apart from placing into $0. Conventionally, it would be a name for the script passed to -c, by analogy with the sh /path/to/script case where $0 is the name or path of the script.

Unlike most commands, -- is treated as an ordinary argument, not as a special-purpose marker. So it's really -- that's used as $0 and not the next argument.

$ sh -c 'echo $1' hello            

$ sh -c 'echo $0' hello
$ sh -c 'echo $0; echo $1' hello world
$ sh -c 'echo $0; echo $1' -- hello

This has nothing to do with xargs, it's passing all of the arguments after sh to the sh command.

| improve this answer | |
  • What's the "name" here? – Melab Sep 19 '17 at 20:23
  • @Melab I meant the argument. It's conventionally a name for the -c script. I've edited my answer. – Gilles 'SO- stop being evil' Sep 20 '17 at 8:52

In the above example the -- is acting as a blocker between sh -c 'echo $(basename $1) ' and file. it's forcing the string file to be the $1 argument to sh.

The above could've been streamlined to this:

$ find . -name "*.txt" | xargs -Ifile sh -c 'echo $(basename file) '
| improve this answer | |

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.