bash 中管道 (|) 和逻辑与 (&&) 的优先级

bash 中管道 (|) 和逻辑与 (&&) 的优先级

具有运算符优先级的经典场景,您有这样的行:

(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是不同的 - 你有一个管道:左边有 subshel​​l,右边有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 5head -n 5ls

答案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没有输出,所以你不会看到任何区别,以太方式。

相关内容