测试 stdin 是文件还是管道还是 tty

Testing whether stdin is a file vs. a pipe vs. a tty

我知道 bash 和 zsh,可以使用例如[ -t 1 ] 确定 STDIN 是否为交互式 tty 会话。

但是,似乎没有办法测试 stdin 是从文件重定向还是从命令输入:

foo < ./file
bar | foo 

有什么方法可以检测出这两者之间的区别吗?另外,是否有任何方法可以获取被重定向的文件的路径(在 /proc/self 之外,这在 macOS 上不可用)?

您可以检查 /dev/stdin 是普通文件还是管道:

$ cat tmp.sh
#!/bin/bash

if [ -f /dev/stdin ]; then
    echo "file"
elif [ -p /dev/stdin ]; then
    echo "pipe"
fi
$ bash tmp.sh < foo.txt
file
$ echo foo | bash tmp.sh
pipe

不过,这取决于 /dev/stdin 在您的文件系统中。

您也可以使用 stat 命令,该命令将 return 没有文件名参数的标准输入的信息。正如您提到的,您使用的是 macOS,您可以使用 %HT 格式:

$ stat -f %HT
Character Device
$ stat -f %HT < foo.txt
Regular File
$ echo foo | stat -f %HT
Fifo File