具有运算符优先级的经典场景,您有这样的行:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
而且你不知道它是否已被解析((A && B) | C)
或(A && B | C)
...
这几乎是官方文档成立这里没有在列表中列出管道,所以我不能简单地签入表中。
此外,在 bash 中,(
不仅可以更改操作顺序,还可以创建一个子shell,所以我不能 100% 确定这行与上一行等效:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
更一般地说,如何知道谷草转氨酶bash 行?在Python中,我有一个函数可以给我树,这样我就可以轻松地仔细检查操作顺序。
答案1
cd ~/screenshots/ && ls screenshot* | head -n 5
这相当于
cd ~/screenshots && { ls screenshot* | head -n 5 ; }
(这大括号将命令组合在一起,无需子 shell)。因此的优先级|
高于&&
和 的优先级(绑定更紧密) ||
。那是,
A && B | C
和
A || B | C
总是意味着仅将 B 的输出提供给 C。如有必要,您可以使用(...)
或{ ... ; }
将命令连接在一起作为单个实体以消除歧义:
{ A && B ; } | C
A && { B | C ; } # This is the default, but you might sometimes want to be explicit
您可以使用一些不同的命令对此进行测试。如果你跑
echo hello && echo world | tr a-z A-Z
然后你会得到
hello
WORLD
后退:tr a-z A-Z
将其输入大写,您可以看到仅echo world
通过管道传输到其中,而echo hello
自己通过了。
这是定义在shell语法,虽然不是很清楚:and_or
产生式 (for &&
/ ||
) 被定义为pipeline
在其主体中有 aa ,而pipeline
只包含command
,其中不contains and_or
- 只有complete_command
产生式可以达到and_or
,并且它只存在于顶层以及结构构造体(如函数和循环)的内部。
您可以手动应用该语法来获取命令的解析树,但 Bash 本身不提供任何内容。我不知道还有哪个 shell 的功能超出了它们自己的解析范围。
shell 语法有很多仅半正式定义的特殊情况,要正确地定义它可能是一项艰巨的任务。甚至 Bash 本身有时会弄错,所以实际情况和理想情况可能会有所不同。
有一些外部解析器尝试匹配语法并生成树,我将广泛推荐这些外部解析器莫比格,试图成为最可靠的。
答案2
长话短说:列出分隔符,例如;
. &
、&&
、 并||
决定解析顺序。
这bash手册告诉我们:
AND 和 OR 列表是一个或多个的序列管道用 && 和 || 分隔分别控制运算符。
或者如何Bash 黑客的 wiki简单地说
<PIPELINE1> && <PIPELINE2>
因此,其中cd ~/screenshots/ && ls screenshot* | head -n 5
有一个管道ls screenshot* | head -n 5
和一个简单的命令cd ~/screenshots/
。注意按照说明书
管道中的每个命令都作为单独的进程(即在子shell 中)执行。
另一方面,(cd ~/screenshots/ && ls screenshot*) | head -n 5
是不同的 - 你有一个管道:左边有 subshell,右边有head -n 5
。在这种情况下,使用 OP 的符号将是(A && B) | C
我们再举一个例子:
$ echo foo | false && echo 123 | tr 2 5
$
这里我们有一份清单<pipeline1> && <pipeline2>
。因为我们知道管道的退出状态与最后一个命令相同并false
返回负状态(即失败),所以&&
不会执行右侧。
$ echo foo | true && echo 123 | tr 2 5
153
这里左边的管道有成功退出状态,所以右边的管道被执行,我们看到它的输出。
请注意,shell 语法并不意味着实际的执行顺序。引用其中之一吉尔斯的回答:
管道命令同时运行。当你运行 ps | grep …,ps 或 grep 是否先启动,以及无论如何它们都会继续,这取决于运气(或者是 shell 工作细节与内核内部调度程序微调相结合的问题)并发执行。
bash 手册中:
AND 和 OR 列表以左关联性执行。
基于此cd ~/screenshots/ && ls screenshot* | head -n 5
,如果先前的命令成功,cd ~/screenshots/
则将首先执行,但可能是生成的第一个进程,而不是因为它们位于管道中。ls screenshot* | head -n 5
head -n 5
ls
答案3
这是在 中指定的位置bash(1)
:
SHELL GRAMMAR
[...]
Pipelines
A pipeline is a sequence of one or more commands separated by one of
the control operators | or |&.
[...]
Lists
A list is a sequence of one or more pipelines separated by one of the
operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or
<newline>.
因此,&&
分离管道。
答案4
你可以试试echo hello && echo world | less
。您将看到|
具有更高的优先级(命令管道是一个命令)。你的第二个例子是不是相同。然而,因为cd
没有输出,所以你不会看到任何区别,以太方式。