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 / 问题 / 477820
Accepted
I'll Eat My Hat
I'll Eat My Hat
Asked: 2018-10-26 11:18:49 +0800 CST2018-10-26 11:18:49 +0800 CST 2018-10-26 11:18:49 +0800 CST

如何管道命令的标准输出,取决于退出代码的结果

  • 772

从这个问题扩展,我们有一个用例,我们希望根据该命令是成功还是失败来管道命令的标准输出。

我们从一个基本的管道开始

command | grep -P "foo"

但是我们注意到有时command不会向 stdout 输出任何内容,但退出代码为0. 我们想忽略这种情况,仅grep在退出代码为1

对于一个工作示例,我们可以实现如下命令:

OUTPUT=$(command) # exit code is 0 or 1
RESULT=$?
if [ $RESULT -eq 0 ]; then
  return $RESULT; # if the exit code is 0 then we simply pass it forward
else
  grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
fi

但这有许多缺点,即您必须编写脚本,这意味着您不能只在控制台中执行它。也显得有些业余。

为了更简洁的语法,我正在想象一个虚构的三元运算符,如果退出代码是 ,它会通过管道1传递,否则它会向前传递退出代码。

command |?1 grep -P "foo" : $?

是否有一系列运算符和实用程序可以实现此结果?

bash control-flow
  • 2 2 个回答
  • 4048 Views

2 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-10-26T11:23:56+08:002018-10-26T11:23:56+08:00

    管道中的命令同时运行,这就是管道和进程间通信机制的全部意义所在。

    在:

    cmd1 | cmd2
    

    cmd1并cmd2同时启动,对写入cmd2的数据进行处理cmd1。

    如果您只想cmd2在cmd1失败时启动cmd2,cmd1则必须在完成并报告其退出状态后启动,因此您不能使用管道,您必须使用保存所有数据的临时文件cmd1产生了:

     cmd1 > file || cmd2 < file; rm -f file
    

    或者像在您的示例中那样存储在内存中,但是还有许多其他问题(例如$(...)删除所有尾随换行符,并且大多数 shell 无法处理其中的 NUL 字节,更不用说大型输出的缩放问题了)。

    在 Linux 上,使用类似zsh或bash将 here-documents 和 here-strings 存储在临时文件中的 shell,您可以执行以下操作:

    { cmd1 > /dev/fd/3 || cmd2 <&3 3<&-; } 3<<< ignored
    

    让外壳处理临时文件的创建和清理。

    bash 版本 5 现在在创建临时文件后删除了对临时文件的写入权限,因此上述方法不起作用,您需要先恢复写入权限来解决它:

    { chmod u+w /dev/fd/3
      cmd1 > /dev/fd/3 || cmd2 <&3 3<&-; } 3<<< ignored
    

    手动,POSIXly:

    tmpfile=$(
      echo 'mkstemp(template)' |
        m4 -D template="${TMPDIR:-/tmp}/XXXXXX"
    ) && [ -n "$tmpfile" ] && (
      rm -f -- "$tmpfile" || exit
      cmd1 >&3 3>&- 4<&- ||
        cmd2 <&4 4<&- 3>&-) 3> "$tmpfile" 4< "$tmpfile"
    

    一些系统有一个非标准mktemp命令(尽管系统之间的接口有所不同),这使得临时文件的创建更容易一些(tmpfile=$(mktemp)对于大多数实现来说应该足够了,尽管有些不会创建文件,所以你可能需要调整umask)。兼容的实现[ -n "$tmpfile" ]应该不需要m4,但 GNU至少不兼容,因为它在调用失败m4时不会返回非零退出状态。mkstemp()

    另请注意,没有什么可以阻止您在控制台中运行任何代码。您的“脚本”可以在交互式外壳的提示下输入相同的内容(return假设代码在函数中的部分除外),但您可以将其简化为:

    output=$(cmd) || grep foo <<< "$output"
    
    • 18
  2. muru
    2018-10-27T02:07:15+08:002018-10-27T02:07:15+08:00

    注意:由于问题被标记为bash,我假设您可以使用 bash 功能。

    鉴于您的示例代码,您似乎想要做的是:

    • 如果为 0,则使用命令的退出状态,
    • 否则使用grep' 退出状态。

    在空管道上运行grep不会花费您任何费用,因此一种选择是无论如何都要通过管道传输它,并检查命令的退出状态,您可以使用PIPESTATUSbash 中的数组来获取它:

    $ (echo foo; exit 1) | grep foo
    foo
    $ echo "${PIPESTATUS[@]}"
    1 0  
    

    这里,subshel​​l 以 1 退出,grep 以 0 退出。

    因此,您可以执行以下操作:

    (command | grep -P "foo"; exit "$((PIPESTATUS[0] ? $? : 0))")
    

    表达式可以简化,但你明白了。


    还可以选择简单地伪造输出:

    (command && echo foo) | grep -P foo
    

    whereecho foo仅当命令成功时才会运行,从而使 grep 也成功。

    • 5

相关问题

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

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

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

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

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

Sidebar

Stats

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

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

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

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

    • 5 个回答
  • Marko Smith

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

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • 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
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +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