如果标准输入为空,如何断开管道?

How to break pipe if stdin is empty?

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

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

感谢任何反馈。

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

$ echo ok | awk '{print [=10=],"1"}' | awk '{print [=10=],"2"}' | awk '{print [=10=],"3"}'
ok 1 2 3

现在添加 grep:

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

并测试空回显:

$ echo | awk '{print [=12=],"1"}' | awk '{print [=12=],"2"}' | awk '{print [=12=],"3"}'
 1 2 3

$ echo | grep -Ei '^.+$' | awk '{print [=12=],"1"}' | awk '{print [=12=],"2"}' | awk '{print [=12=],"3"}'

看起来这行得通,但行不通,这确实很有趣,好吧,显然管道不适合这里,试试这个方法:

#!/bin/bash
set -x

fun(){
    data=$(echo ""); [[ $data ]] && data=$(awk '{print [=13=],1}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print [=13=],2}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print [=13=],3}' <<< "$data") || return 1; echo "$data"
}

fun ok
fun

测试:

$ ./test 
+ fun ok
++ echo ok
+ data=ok
+ [[ -n ok ]]
++ awk '{print [=14=],1}'
+ data='ok 1'
+ [[ -n ok 1 ]]
++ awk '{print [=14=],2}'
+ data='ok 1 2'
+ [[ -n ok 1 2 ]]
++ awk '{print [=14=],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 "")
    [[ $data ]] && data=$(awk '{print [=15=],1}' <<< "$data") || return 1
    [[ $data ]] && data=$(awk '{print [=15=],2}' <<< "$data") || return 1
    [[ $data ]] && data=$(awk '{print [=15=],3}' <<< "$data") || return 1
        echo     "$data"
}

fun ok
fun

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

$ command1 | ifne command2 | ifne command3 | ifne command4

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