具有运算符优先级的经典场景,您有如下一行:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
而且你不知道它是否被解析((A && B) | C)
或(A && B | C)
......
在这里找到的几乎官方文档没有在列表中列出管道,所以我不能简单地检查表。
此外,在 bash 中,(
不仅用于更改操作顺序,而且还创建了一个 subshel l ,因此我不能 100% 确定此行与上一行等效:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
更一般地说,如何知道bash 行的AST ?在 python 中,我有一个函数可以给我树,以便我可以轻松地仔细检查操作顺序。
这相当于
(大括号将命令组合在一起,没有 subshell)。因此, 的优先级
|
比&&
和更高(绑定更紧密)||
。那是,和
总是意味着只有 B 的输出将提供给 C。如有必要,您可以使用
(...)
或{ ... ; }
将命令作为单个实体连接在一起以消除歧义:您可以使用一些不同的命令对此进行测试。如果你跑
那么你会得到
back:
tr a-z A-Z
大写它的 input,你可以看到只有echo world
通过管道输入,而echo hello
它自己通过。这是在shell 语法中定义的,虽然不是很清楚:
and_or
产生式 (for&&
/||
) 被定义为pipeline
在其主体中有 aa,而pipeline
只是 containscommand
,它不包含and_or
- 只有complete_command
产生式可以到达and_or
,并且它只存在于顶层和结构构造体内部,如函数和循环。您可以手动应用该语法来获取命令的解析树,但 Bash 本身不提供任何内容。我不知道有任何 shell 超出了他们自己的解析所用的功能。
shell 语法有很多只半正式定义的特殊情况,而且要做到正确可能是一项艰巨的任务。甚至 Bash 本身有时也会出错,因此实用性和理想可能会有所不同。
有尝试匹配语法并生成树的外部解析器,其中我将广泛推荐Morbig,它试图成为最可靠的。
TL;DR:列出分隔符,例如
;
.&
,&&
, 并||
决定解析顺序。bash 手册告诉我们:
或者Bash Hacker 的 wiki简洁地说
因此,
cd ~/screenshots/ && ls screenshot* | head -n 5
有一个管道ls screenshot* | head -n 5
和一个简单的命令cd ~/screenshots/
。请注意,根据手册另一方面,
(cd ~/screenshots/ && ls screenshot*) | head -n 5
是不同的——你有一个管道:左边是 subshell,右边是head -n 5
. 在这种情况下,使用 OP 的符号将是(A && B) | C
让我们再举一个例子:
这里我们有一份清单
<pipeline1> && <pipeline2>
。由于我们知道管道的退出状态与上一个命令相同并false
返回负状态(即失败),&&
因此不会在右侧执行。这里左边的管道有成功退出状态,所以右边的管道被执行,我们看到它的输出。
请注意,shell 语法并不意味着实际的执行顺序。引用吉尔斯的回答之一:
并且来自 bash 手册:
基于此
cd ~/screenshots/ && ls screenshot* | head -n 5
,如果先前的命令成功,cd ~/screenshots/
则将首先执行,但可能是产生的第一个进程,而不是因为它们在管道中。ls screenshot* | head -n 5
head -n 5
ls
这是在 中指定的位置
bash(1)
:因此,
&&
分离管道。你可以试试
echo hello && echo world | less
。您会看到它|
具有更高的优先级(命令管道是命令)。你的第二个例子不一样。但是因为cd
没有输出,所以你不会看到任何区别,以太方式。