1

From POSIX 2013:

The XSI extensions specifying the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent. (Many expressions using them are ambiguously defined by the grammar depending on the specific expressions being evaluated.) Scripts using these expressions should be converted to the forms given below. Even though many implementations will continue to support these obsolescent forms, scripts should be extremely careful when dealing with user-supplied input that could be confused with these and other primaries and operators. Unless the application developer knows all the cases that produce input to the script, invocations like:

test "$1" -a "$2"

should be written as:

test "$1" && test "$2"

  1. "the '(' and ')' operators have been marked obsolescent".

    Are ( and ) the operators that group commands, and create subshell?

    If they are obsolete, what are their replacement?

  2. Should test "$1" -a "$2" be replaced by test "$1" && test "$2", or by (( test "$1" && test "$2" ))?

    Don't we need the ((...)) to return 0 or 1 just like test in the original command does?

6

Are ( and ) the operators that group commands, and create subshell?

No, the document refers to the operators to group expressions using test:

test 0 -eq 0 -a \( 0 -eq 1 -o 1 -eq 1 \)

If they are obsolete, what are their replacement?

Their replacement are () and {}, which, similarily, group commands at the shell's level:

test 0 -eq 0 && (test -0 -eq 1 || test 1 -eq 1)
test 0 -eq 0 && { test -0 -eq 1 || test 1 -eq 1; }

It's pretty easy to see the pattern: every operator used in test for expressions is replaced with the shell's equivalent for commands.

Should test "$1" -a "$2" be replaced by test "$1" && test "$2", or by (( test "$1" && test "$2" ))?

It should be replaced with test "$1" && test "$2"; (()) is used for arithmetic expansion and has no bearing with commands' exit status, as its purpose is to evaluate arithmetic expressions. For example this would be valid:

(( $(test 1 -eq 1 && echo $?) && $(test 0 -eq 0 && echo $?) ))

(notice the command substitutions, which are replaced with the inner commands' exit statuses, 0 and 0; the evaluated expression is actually (( 0 && 0 ))).

But this causes a syntax error:

(( test 1 -eq 1 && test 0 -eq 0 ))
$ (( test 1 -eq 1 && test 0 -eq 0 ))
bash: ((: test 1 -eq 1 && test 0 -eq 0 : syntax error in expression (error token is "1 -eq 1 && test 0 -eq 0 ")
| improve this answer | |
1

To emphasize a very important fact in simpler language:

The characters you type on the screen may or may not be "seen" (received) by the command you are invoking. You're probably familiar with this; it happens every time you quote something.

The shell sees every character you type. The shell has its own rules for what it does with those characters. For instance, the echo command "sees" the exact same thing in each of the following instances:

$ echo hello
hello
$ echo "hello"
hello
$ echo 'hello'
hello
$ echo \h\e\l\l\o
hello
$ echo 'h'"e"\l$'lo'
hello
$ somevar=hello;echo $somevar
hello
$ somevar='h'"el"\l\o;echo $somevar
hello
$ 

Just in the way that the quotes and backslashes in the above are never "seen" by the echo command, the shell handles parentheses specially. So, when unquoted, they don't get seen by anything but the shell.

A good example of this is the find command, which accepts parentheses as arguments. For the parentheses to reach the find command and not be interpreted specially by the shell, they must be quoted or escaped to remove their special meaning to the shell. Note that the quotes and the escapes do not reach the find command; only the parentheses do:

(From another question on this site:)

# What you type:
find ~ \( -type f '-ex'ec ch\mod 600 {} + ')' -o \
       "(" -type d -exec c"hmo"d 700 {} ';' \)
# What the find command sees:
/home/tim ( -type f -exec chmod 600 {} + ) -o ( -type d -exec chmod 700 {} ; )
# If you typed this...
find ~ \( -type f -exec chmod 600 {} + ) -o \
       \( -type d -exec chmod 700 {} + \)
# ...find doesn't see anything, because bash runs into an error condition
# before it can even parse the line.  That close paren is special to bash.

There is a slang term related to this, also. When you intend to have a command "see" a special character (usually a single quote or double quote, but also can include backslashes or space characters) and due to an error in your quoting and escaping, the command never sees that character, we say that the shell "ate" the quoting.

A fun* example of quote-eating (and the difficulties that can surround it) include: Write an ssh command that will log into a remote server, start a bash session, and run a sed command to modify an SQL query that is stored in a file so that it is quoted correctly for inclusion in an HTTP message.


With that all said, here is the short answer to:

  1. "the '(' and ')' operators have been marked obsolescent".

Are ( and ) the operators that group commands, and create subshell?

If they are obsolete, what are their replacement?

The parentheses still have special meaning to the shell, and that is not obsolete. What is obsolete is passing parentheses through to the test command (by quoting them to prevent the shell from eating them).


*This clearly depends on your definition of "fun."

| improve this answer | |
  • This seems (at least on superficial reading) correct but has nothing whatsoever to do with the question! – Celada Mar 19 '16 at 19:47
  • @Celada, I thought it was implicit in my explanation but I have added the answer (and relevance) explicitly now. :) – Wildcard Mar 19 '16 at 23:38
  • Don't worry. Say whatever you say. I never downvote. – Tim Mar 20 '16 at 0:39

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.