The classic scenario with Operator Precedence, you have a line like :
(cd ~/screenshots/ && ls screenshot* | head -n 5)
And you don't know if it's parsed ((A && B) | C)
or (A && B | C)
…
The almost official documentation found here doesn't list the pipe in the list so I cannot simply check in the table.
Furthermore in bash, (
is not only for changing the order of operations but creates a subshell, so I'm not 100% sure this lines is the equivalent of the previous line :
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
More generally, how to know the AST of a bash line? In python I have a function that gives me the tree so that I can easily double check the order of operation.
Best Answer
This is equivalent to
(the braces group commands together without a subshell). The precedence of
|
is thus higher (binds tighter) than&&
and||
. That is,and
always mean that only B's output is to be given to C. You can use
(...)
or{ ... ; }
to join commands together as a single entity for disambiguation if necessary:You can test this out using some different commands. If you run
then you'll get
back:
tr a-z A-Z
upper-cases its input, and you can see that onlyecho world
was piped into it, whileecho hello
went through on its own.This is defined in the shell grammar, although not terribly clearly: the
and_or
production (for&&
/||
) is defined to have a apipeline
in its body, whilepipeline
just containscommand
, which doesn't containand_or
- only thecomplete_command
production can reachand_or
, and it only exists at the top level and inside the bodies of structural constructs like functions and loops.You can manually apply that grammar to get a parse tree for a command, but Bash doesn't provide anything itself. I don't know of any shell that does beyond what's used for their own parsing.
The shell grammar has a lot of special cases defined only semi-formally and it can be quite a mission to get right. Even Bash itself has sometimes gotten it wrong, so the practicalities and the ideal may be different.
There are external parsers that attempt to match the syntax and produce a tree, and of those I will broadly recommend Morbig, which attempts to be the most reliable.