如果你只需要知道它是管道还是重定向,那么判断标准输入是否为终端就足够了:
if [ -t 0 ]; then
else
fi
[
(也称为test
)加上-t
等效于libc的isatty()
函数。以上命令可同时适用于something | myscript
和myscript < infile
。这是最简单的解决方案,假设您的脚本是用于交互式使用。
[
命令是bash和其他一些shell内置的,由于[
/test
与-t
在POSIX中,因此它也是可移植的(不依赖于Linux、bash或GNU实用程序特性)。
有一种边缘情况,如果文件描述符无效,则test -t
也会返回false,但需要进行一些轻微的调整才能安排。test -e
将检测到这一点,尽管假定您有一个文件名(例如/dev/stdin
)可供使用。
POSIXtty
命令也可以使用,并处理上述问题。如果stdin是终端,则它将打印tty设备名称并返回0,并在任何其他情况下打印“not a tty”并返回1:
if tty >/dev/null ; then
else
fi
(使用GNU tty
,您可以使用tty -s
进行静默操作)
一种不太便携的方法,但在典型的Linux上肯定可行,是使用GNU的stat
和它的%F
格式说明符,这会返回文本"character special file"、"fifo"和"regular file",分别对应于终端、管道和重定向。 stat
需要一个文件名,因此您必须提供一个特殊命名的文件,形式为/dev/stdin
、/dev/fd/0
或/proc/self/fd/0
,并使用-L
来追踪符号链接:
stat -L -c "%F" /dev/stdin
这可能是处理非交互式使用(因为您无法对终端进行假设)或检测实际管道(FIFO)与重定向不同的最佳方法。使用% F存在一种小问题,即您不能将其用于区分终端和某些其他设备文件,例如/dev/zero或/dev/null,它们也是“字符特殊文件”,并且可能合理地出现。一个不太好看的解决方案是使用% t来报告底层设备类型(十六进制中的主要设备号),假设您知道底层tty设备号范围…这取决于您是否使用BSD样式pty还是Unix98样式pty,或者您是否在实际控制台上等等。在简单情况下,% t将为0,但适用于常规(非特殊)文件的管道或重定向。
解决此类问题的更一般方法是使用带有超时的bash read(read -t 0 ...)或具有GNU dd的非阻塞I / O(dd iflag = nonblock)。后者将使您能够检测stdin上的输入缺失,如果没有准备好读取,则dd将返回退出代码1。然而,这些更适合于非阻塞轮询循环,而不是一次性检查:当您在管道中启动两个或多个进程时,存在竞争条件,因为一个进程可能准备好读取,而另一个进程尚未写入。
your_script <<< 'some string'
-- 你的脚本将把它视为来自标准输入的普通输入。 - jfs