AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 497543
Accepted
Robert Vanden Eynde
Robert Vanden Eynde
Asked: 2019-01-30 12:25:04 +0800 CST2019-01-30 12:25:04 +0800 CST 2019-01-30 12:25:04 +0800 CST

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

  • 772

具有运算符优先级的经典场景,您有如下一行:

(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 中,我有一个函数可以给我树,以便我可以轻松地仔细检查操作顺序。

bash
  • 4 4 个回答
  • 15060 Views

4 个回答

  • Voted
  1. Best Answer
    Michael Homer
    2019-01-30T13:10:45+08:002019-01-30T13:10:45+08:00
    cd ~/screenshots/ && ls screenshot* | head -n 5
    

    这相当于

    cd ~/screenshots && { ls screenshot* | head -n 5 ; }
    

    (大括号将命令组合在一起,没有 subshel​​l)。因此, 的优先级|比&&和更高(绑定更紧密) ||。那是,

    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
    

    back:tr a-z A-Z大写它的 input,你可以看到只有echo world通过管道输入,而echo hello它自己通过。


    这是在shell 语法中定义的,虽然不是很清楚:and_or产生式 (for &&/ ||) 被定义为pipeline在其主体中有 aa,而pipeline只是 contains command,它不包含and_or- 只有complete_command产生式可以到达and_or,并且它只存在于顶层和结构构造体内部,如函数和循环。

    您可以手动应用该语法来获取命令的解析树,但 Bash 本身不提供任何内容。我不知道有任何 shell 超出了他们自己的解析所用的功能。

    shell 语法有很多只半正式定义的特殊情况,而且要做到正确可能是一项艰巨的任务。甚至 Bash 本身有时也会出错,因此实用性和理想可能会有所不同。

    有尝试匹配语法并生成树的外部解析器,其中我将广泛推荐Morbig,它试图成为最可靠的。

    • 37
  2. Sergiy Kolodyazhnyy
    2019-01-30T12:47:03+08:002019-01-30T12:47:03+08:00

    TL;DR:列出分隔符,例如;. &, &&, 并||决定解析顺序。

    bash 手册告诉我们:

    AND 和 OR 列表是由 && 和 || 分隔的一个或多个管道的序列。分别控制操作员。

    或者Bash Hacker 的 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

    • 10
  3. JoL
    2019-01-30T14:11:10+08:002019-01-30T14:11:10+08:00

    这是在 中指定的位置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>.
    

    因此,&&分离管道。

    • 6
  4. ctrl-alt-delor
    2019-01-30T12:31:48+08:002019-01-30T12:31:48+08:00

    你可以试试echo hello && echo world | less。您会看到它|具有更高的优先级(命令管道是命令)。你的第二个例子不一样。但是因为cd没有输出,所以你不会看到任何区别,以太方式。

    • 2

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve