如何检查管道是否为空,如果不是则对数据运行命令?

如何检查管道是否为空,如果不是则对数据运行命令?

我已经在 bash 脚本中通过管道传输了一行,并想在将其提供给程序之前检查管道是否有数据。

我搜索了一下,test -t 0但在这里不起作用。总是返回 false。那么如何确定管道有数据呢?

例子:

echo "string" | [ -t 0 ] && echo "empty" || echo "fill"

输出:fill

echo "string" | tail -n+2 | [ -t 0 ] && echo "empty" || echo "fill"

输出:fill

不像标准/规范的方法来测试上述管道是否产生输出?需要保留输入以将其传递给程序。这概括了如何将输出从一个进程传输到另一个进程,但仅在第一个进程有输出时才执行?其重点是发送电子邮件。

答案1

无法使用常用的 shell 实用程序来查看管道的内容,也没有可移植的方法从管道中读取字符然后将其放回。知道管道有数据的唯一方法是读取一个字节,然后必须将该字节发送到其目的地。

所以就这样做:读取一个字节;如果检测到文件结尾,则在输入为空时执行您想要执行的操作;如果您确实读取了一个字节,则在输入不为空时分叉您想要执行的操作,将该字节通过管道传输到其中,然后通过管道传输其余数据。

first_byte=$(dd bs=1 count=1 2>/dev/null | od -t o1 -A n | tr -dc 0-7)
if [ -z "$first_byte" ]; then
  # stuff to do if the input is empty
else
  {
    printf "\\$first_byte"
    cat
  } | {
    # stuff to do if the input is not empty
  }      
fi

ifne效用来自Joey Hess 的 moreutils如果输入不为空,则运行命令。默认情况下通常不会安装它,但它应该可以在大多数 UNIX 变体上使用或轻松构建。如果输入为空,ifne则不执行任何操作并返回状态0,无法与命令运行成功区分开。如果你想在输入为空时执行某些操作,则需要安排命令不返回 0,这可以通过让成功案例返回可区分的错误状态来完成:

ifne sh -c 'do_stuff_with_input && exit 254'
case $? in
  0) echo empty;;
  254) echo success;;
  *) echo failure;;
esac

test -t 0与此无关;它测试标准输入是否是终端。它没有以任何方式说明任何输入是否可用。

这里任意选择 254,避免使用 255,因为执行某些命令exit(-1)(通常会导致$?255)相对常见(-exec(-2)不太常见)。

答案2

一个简单的解决方案是使用ifne命令(如果输入不为空)。在某些发行版中,默认情况下不安装它。它是大多数发行版中软件包的一部分moreutils

ifne当且仅当标准输入不为空时运行给定命令

请注意,如果标准输入不为空,则会传递ifne给给定的命令

答案3

检查 stdin (0) 的文件描述符是打开还是关闭:

[ ! -t 0 ] && echo "stdin has data" || echo "stdin is empty"

答案4

老问题,但万一有人像我一样遇到它:我的解决方案是超时阅读。

while read -t 5 line; do
    echo "$line"
done

如果stdin为空,则 5 秒后返回。否则它将读取所有输入,您可以根据需要对其进行处理。

在这些受支持的情况下-t,您可以在使用 读取任何数据之前测试输入-t0。 (还指定-u0STDIN,因为 awslinux 需要它,而 ubuntu 则假定它)

if [ $(read -u0 -t0) ]; then ....

之后你就可以开始正常阅读了

help read

如果 TIMEOUT 为 0,则 read 立即返回,而不尝试读取任何数据,仅当指定文件描述符上的输入可用时才返回成功。

相关内容