3

I am reading the bash source code, and the BNF grammar for bash would be:

<pipeline_command> ::= <pipeline>
                    |  '!' <pipeline>
                    |  <timespec> <pipeline>
                    |  <timespec> '!' <pipeline>
                    |  '!' <timespec> <pipeline>

<pipeline> ::=
          <pipeline> '|' <newline_list> <pipeline>
       |  <command>

Does this means ! command is a kind of pipe too.

! ls works, however it's the same as ls.

! time ls works too.

That's quite different to | pipe.

How to use ! in bash? Is it a pipe?

  • The output of ! ls and ls are the same; the exit status are different. – chepner Nov 26 '17 at 15:30
6

From the bash manual: "If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status"

You are misreading the grammar. What the grammar says is that you can put a ! in front of a pipeline, not replace | with a !.

4

The exclamation point just logically reverses the return code of the command/pipeline (see e.g. Bash's manual):

if true ;    then echo this prints ; fi
if ! false ; then echo this also prints ; fi
if ! true ;  then echo this does not print ; fi

The return code of a pipeline is (usually) just the return code of the last command, so the bang inverts that:

if ! true | false ; then echo again, this also prints ; fi
2

Defining a pipeline to be one or more commands means a single command is also a pipeline, albeit one that doesn't actually involve a pipe. The benefit is that ! as a negation operator doesn't have to be defined separately for commands and pipelines; it need only be defined as applying to a pipeline.

In ! cmd1 | cmd2, the ! negates the exit status of the entire pipeline, not just the single command cmd1. The exit status of a pipeline, by default, is the exit status of the right-most command.


Likewise, a list is one more pipelines joined by ;, &, &&, or ||. Thus, a single pipeline is also a list, and a single command is also a list. Then, when a command like if is defined as taking a list between the if and then keywords, this automatically includes single commands and single pipelines as part of the definition of a command.

  • A list consisting of two pipelines (one of which only consists of one command):

    if IFS= read -r response && echo "$response" | grep foo; then
    
  • A list consisting of a single pipeline:

    if echo "$foo" | grep foo; then
    
  • A list consisting of single pipeline (which itself contains only a single command):

    if true; then
    
2

A couple of points to add to what the other answers said:

  • As noted (indirectly) by chepner’s answer, the ! operator is defined as an optional prefix to the <pipeline_command> syntactic element, rather than to <command>.  This has the consequence that you cannot say

      cmd1 | ! cmd2
    

    or

    ! cmd1 | ! cmd2
    

    You can only negate the exit status of an “entire pipeline”.  As chepner pointed out, a “pipeline” can be a single command, so you can do things like

    ! cmd1 && ! cmd2; ! cmd3 || ! cmd4
    

    but that’s silly.  The ! before cmd2 does nothing whatsoever; the ! before cmd4 affects only the value of $? at the end of the command, and the other two can be eliminated by exchanging the AND and the OR:

      cmd1  ||  cmd2;   cmd3  &&  cmd4
    

    Similarly, while ! cmd can be replaced with until cmd.

  • A <pipeline> preceded by a ! becomes a <pipeline_command> — a different syntactic element.  Therefore, it is not valid to say

    ! ! cmd1
    

    unlike arithmetic expansion, where things like $((! ! value)) and $((! ! ! value)) are valid.

  • Be advised that POSIX defines the same grammar, but uses different element names.  The BNF in the question appears in POSIX as

    pipeline         :      pipe_sequence
                     | Bang pipe_sequence
    
    pipe_sequence    :                             command
                     | pipe_sequence '|' linebreak command
    

    where Bang is a %token with the value '!'.

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.