使管道以非空退货为条件


Answers:


9

以下ifnotempty函数将其输入传递给作为参数传递的命令,但如果输入为空则不执行任何操作。用它通过写入来source --foo插入。sink --barsource --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
}

设计注意事项:

  • 我希望该实现在所有POSIX / Unix平台上都可以运行,尽管严格说来它不符合标准:它依赖于dd读取的字节数不超过其在标准输入中读取的一个字节。
  • 我认为head -c 1这将是dd bs=1 count=1 2>/dev/nullLinux上的合适替代品。
  • 另一方面,head -n 1这是不合适的,因为head通常会缓冲其输入并且可能读取的内容多于其输出的一行,并且由于它是从管道读取的,因此多余的字节只会丢失。
  • read -r head甚至read -r -n 1 head不适合此处,因为如果第一个字符是换行符,head则将其设置为空字符串,从而无法区分空输入和以空行开头的输入。
  • 我们不能只是写,head=$(head -c 1)因为如果第一个字符是换行符,则命令替换将剥离最后的换行符,从而使得无法区分空输入和以空行开头的输入。
  • 在bash和ksh或zsh的,可以取代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
}

17

这应该为你工作

$ --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.


4

下面的函数尝试读取第一个字节,如果成功,则回显该字节并保留其余字节。应该高效并且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。它认为linehere都是电子邮件的收件人,而不是主题中的令牌。我必须逃避"周围的问题才能使其正常工作。但是,pipe_if_not_empty即使没有转义,接受的答案中的功能对我也有效。
kuzzooroo 2014年

2

至少这样的工作:

yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi

请注意,以上内容将换行符和其他特殊字符视为输出,因此传递给该if语句的空行将被视为输出。如果您的输出通常应该大于1个字节,请提高-gt限制:)


yourothercommand从未看到的输出yourcommand
暂停,直到另行通知。

2

代替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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.