【问题标题】:How to break pipe if stdin is empty?如果标准输入为空,如何断开管道?
【发布时间】:2021-05-27 18:36:47
【问题描述】:

如果标准输入为空,我想打破整个管道。我尝试将 xargs -r 和 tee 结合起来,这意味着如果 stdin 为空则不打印和写入,但它失败了

...| upstream commands | xargs -r tee output.txt | downstream commands | ...

感谢任何反馈。

【问题讨论】:

标签: bash shell pipe xargs tee


【解决方案1】:

您实际上无法有条件地终止 bash 管道。管道中的所有命令同时启动。但是,有一个工具可以帮助您创建 条件 管道。在moreutils 中,您可以找到工具ifne,当且仅当输入/dev/stdin 不为空时,该工具才会执行命令。所以你可以这样写:

$ command1 | ifne command2 | ifne command3 | ifne command4

这里所有命令ifnecommand1 都是同时启动的。只有当ifne通过/dev/stdin接收输入时,它才会启动其各自的commandx

【讨论】:

    【解决方案2】:

    如果命令失败,管道会破裂。您可以在两者之间添加 grep 来实现这一点。一个例子:

    $ echo ok | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
    ok 1 2 3
    

    现在添加 grep:

    $ echo ok | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
    ok 1 2 3
    

    并测试空回声:

    $ echo | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
     1 2 3
    
    $ echo | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
    

    看起来这行得通,但行不通,确实很有趣,那么 obvy 管道不适合这里,试试这个方法:

    #!/bin/bash
    set -x
    
    fun(){
        data=$(echo "$1"); [[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1; echo "$data"
    }
    
    fun ok
    fun
    

    测试:

    $ ./test 
    + fun ok
    ++ echo ok
    + data=ok
    + [[ -n ok ]]
    ++ awk '{print $0,1}'
    + data='ok 1'
    + [[ -n ok 1 ]]
    ++ awk '{print $0,2}'
    + data='ok 1 2'
    + [[ -n ok 1 2 ]]
    ++ awk '{print $0,3}'
    + data='ok 1 2 3'
    + echo 'ok 1 2 3'
    ok 1 2 3
    + fun
    ++ echo ''
    + data=
    + [[ -n '' ]]
    + return 1
    

    更易读的变体:

    #!/bin/bash
    set -x
    
    fun(){
            data=$(echo "$1")
        [[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1
        [[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1
        [[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1
            echo     "$data"
    }
    
    fun ok
    fun
    

    【讨论】:

    • 这不会破坏管道,它仍然会执行每个命令。这个想法不是执行命令
    • 正如@kvantour 所说,实际上我想在最后一个标准输出为空的情况下中断以下命令,以避免循环中的 tee 生成大量空文件。
    猜你喜欢
    • 1970-01-01
    • 2016-04-06
    • 2020-05-11
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多