I want to call /bin/sh, and use the -c option to pass the command '+x', i.e., to execute a program called '+x', whose name begins with a plus sign.
Since '+x' is interpreted by /bin/sh as an option (specifically, disable the 'x' option), /bin/sh must be prevented from interpreting it as an option. I get the following different results depending on the /bin/sh I use:
(1) First variant:
/bin/sh -c -- +x
Using Dash and Bash on Linux: The command +x is executed.
Using FreeBSD's sh: The command -- is executed, and the +x option is set.
(2) Second variant:
/bin/sh -c +x
Using Dash and Bash on Linux: The +x option is set, and there is an error because the option -c is missing an argument.
Using FreeBSD's sh: The command +x is executed.
(3) Third variant:
/bin/sh -c - +x
Using Dash and Bash on Linux: +x is executed.
Using FreeBSD's sh: The command - is executed and the option +x is set.
(4) Fourth variant: (ADDED as suggested in the comments)
/bin/sh -c+x
Using Dash and Bash on Linux: Invalid/Illegal option '+'
Using FreeBSD's sh: Bad -c option
My question: What does POSIX prescribe?
I'm reading the POSIX specification for sh here: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html
Quoting from it: "A single hyphen shall be treated as the first operand and then ignored. If both '-' and "--" are given as arguments, or if other operands precede the single hyphen, the results are undefined."
I'm not sure whether that quote also applies to a single dash placed just after '-c'.
So, which one is right, Dash/Bash or FreeBSD? Or, if both are right because POSIX allows both, how to do this portably?
The answer to the question "What does Posix prescribe" is already present in the OP. But the important feature of the Posix standard is not highlighted: the -c
option does not take an argument.
You can see this in the Synopsis:
sh -c [-abCefhimnuvx] [-o option]... [+abCefhimnuvx] [+o option]...
command_string [command_name [argument...]]
What the -c
flag does is cause the positional parameters ("operands") to be interpreted in a different way. Without -c
, they are interpreted as [command_file [argument...]]
:
sh [-abCefhimnuvx] [-o option]... [+abCefhimnuvx] [+o option]...
[command_file [argument...]]
That, by the way, is why sh -c+x
is an error. If -c
took an argument, then it would be legal to include the argument in the same word.
So, to answer the more specific questions:
Posix says "A single hyphen shall be treated as the first operand and then ignored...". Does that apply to a -
immediately following -c
?
A: Yes, it does. -c
is a complete option, and the -
is therefore an operand. By contrast, -
in -o -
would not be treated as an operand. (It would be treated as an invalid option name.)
Which one is right, Dash/Bash or FreeBSD?
A: In this case, Dash and Bash are Posix-compliant, and FreeBSD's sh is not. FreeBSD's shell considerably predates the current Posix specification, and I don't believe it ever purported to be fully compliant to any Posix specification.
How do I portably use sh
to run a command whose name begins with a +
?
A: I would think the following would work on any shell:
sh -c " +x"
" +x"
will not be recognized as an option because it doesn't start with a +
or -
, and sh -c
causes the operand to be parsed as a shell command, so leading whitespace will be ignored. I don't have a copy of FreeBSD's ash
to play with just now, so I welcome corrections.
Or you could use a simple compound command:
sh -c "{ +x; }"
Possibly clearest (assuming the shell you're using implements the Posix-standard builtin command
) is:
sh -c "command +x"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With