Answers:
以下ifnotempty
函数将其输入传递给作为参数传递的命令,但如果输入为空则不执行任何操作。用它通过写入来source --foo
插入。sink --bar
source --foo | pipe_if_not_empty sink --bar
pipe_if_not_empty () {
head=$(dd bs=1 count=1 2>/dev/null; echo a)
head=${head%a}
if [ "x$head" != x"" ]; then
{ printf %s "$head"; cat; } | "$@"
fi
}
设计注意事项:
dd
读取的字节数不超过其在标准输入中读取的一个字节。head -c 1
这将是dd bs=1 count=1 2>/dev/null
Linux上的合适替代品。head -n 1
这是不合适的,因为head
通常会缓冲其输入并且可能读取的内容多于其输出的一行,并且由于它是从管道读取的,因此多余的字节只会丢失。read -r head
甚至read -r -n 1 head
不适合此处,因为如果第一个字符是换行符,head
则将其设置为空字符串,从而无法区分空输入和以空行开头的输入。head=$(head -c 1)
因为如果第一个字符是换行符,则命令替换将剥离最后的换行符,从而使得无法区分空输入和以空行开头的输入。cat
通过</dev/stdin
对微观性能增益。如果您不介意将整个中间数据存储在内存中,则这是的非常简单的实现pipe_if_not_empty
。
pipe_if_not_empty () {
input=$(cat; echo a);
if [ "x$input" != x"a" ]; then
{ printf %s "${input%a}"; } | "$@"
fi
}
这是一个稍微简单的实现,但要注意以下几点:
同样,整个数据都存储在内存中。
pipe_if_not_empty () {
input=$(cat);
if [ "x$input" != x"" ]; then
{ printf '%s\n' "${input}"; } | "$@"
fi
}
这应该为你工作
$ --a function-- | [ xargs -r ] --another function--
一个例子
$ echo -e "\n\n" | xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1" | xargs -r ls
ls: cannot access 1: No such file or directory
很简单,但它应该对您有用。如果您的“函数”在管道中发送空字符串或什至换行符,则xargs -r将阻止传递给“另一个函数”。
xargs的参考:http : //www.oreillynet.com/linux/cmd/cmd.csp? path = x/xargs
-r, --no-run-if-empty
Do not run command if standard input contains only blanks.
下面的函数尝试读取第一个字节,如果成功,则回显该字节并保留其余字节。应该高效并且100%可移植。
if_read() {
IFS="" read -rN 1 BYTE && { echo -nE "$BYTE"; cat; } | "$@";
}
测试用例:
$ echo -n | if_read wc -c
$ echo | if_read wc -c
1
$ echo -en "\nX" | if_read wc -c
2
$
echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com
。它认为line
和here
都是电子邮件的收件人,而不是主题中的令牌。我必须逃避"
周围的问题才能使其正常工作。但是,pipe_if_not_empty
即使没有转义,接受的答案中的功能对我也有效。
至少这样的工作:
yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi
请注意,以上内容将换行符和其他特殊字符视为输出,因此传递给该if语句的空行将被视为输出。如果您的输出通常应该大于1个字节,请提高-gt限制:)
yourothercommand
从未看到的输出yourcommand
。
代替sender | receiver
:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | receiver; fi; }
sender | tester
或者,您可以通过将其更改为接受接收程序作为参数来实现更通用的目的,如Gilles的答案:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver