Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling of '--' in arguments of /bin/sh: POSIX vs implementations by Bash/Dash/FreeBSD's sh

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?

like image 893
Jérôme Kunegis Avatar asked Jun 17 '16 16:06

Jérôme Kunegis


1 Answers

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:

  1. 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.)

  2. 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.

  3. 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"
    
like image 142
rici Avatar answered Sep 30 '22 17:09

rici