[[ -t 1 ]] && \
echo 'STDOUT is attached to TTY'
[[ -p /dev/stdout ]] && \
echo 'STDOUT is attached to a pipe'
[[ ! -t 1 && ! -p /dev/stdout ]] && \
echo 'STDOUT is attached to a redirection'
字符串 在Linux上,它工作得很好:
:$ ./bash_redir_test.sh
STDOUT is attached to TTY
:$ ./bash_redir_test.sh | xargs echo
STDOUT is attached to a pipe
:$ rm bash_redir_test.log
:$ ./bash_redir_test.sh >> bash_redir_test.log
:$ tail bash_redir_test.log
STDOUT is attached to a redirection
型 在Solaris上:
:# ./bash_redir_test.sh
STDOUT is attached to TTY
:# ./bash_redir_test.sh | xargs echo
STDOUT is attached to a redirection
:# rm bash_redir_test.log
bash_redir_test.log: No such file or directory
:# ./bash_redir_test.sh >> bash_redir_test.log
:# tail bash_redir_test.log
STDOUT is attached to a redirection
:#
6条答案
按热度按时间50pmv0ei1#
在纯POSIX shell中,
字符串
会传回“terminal”,因为输出会传送到您的终端机,而
型
会传回“not a terminal”,因为括号元素的输出会以管道传送至
cat
。手册页中对
-t
标志进行了如下描述-t fd如果文件描述符fd是打开的并且指向一个终端,则为True。
......其中
fd
可以是常用的文件描述符分配之一:doinxwow2#
没有一种万无一失的方法来确定STDIN、STDOUT或STDERR是否通过管道与您的脚本连接,这主要是因为
ssh
之类的程序。正常工作的东西
例如,下面的bash解决方案可以在交互式shell中正常工作:
字符串
但它们并不总是有效
但是,当将此命令作为非TTY
ssh
命令执行时,STD流 * 总是 * 看起来像是通过管道传输的。为了演示这一点,使用STDIN,因为它更容易:型
为什么重要
这是一个相当大的问题,因为它意味着bash脚本无法判断是否正在通过管道传输非tty
ssh
命令。请注意,当ssh
的最新版本开始为非TTY STDIO使用管道时,引入了这种不幸的行为。以前的版本使用套接字,可以通过使用[[ -S ]]
与bash中的套接字区分开来。When it matters
当您想要编写一个行为类似于编译实用程序(如
cat
)的bash脚本时,这种限制通常会导致问题。例如,cat
在同时处理各种输入源时允许以下灵活行为,并且无论使用的是非TTY还是强制TTYssh
,它都足够智能,可以确定是否正在接收管道输入:型
只有在能够可靠地确定是否涉及管道的情况下,才能执行类似的操作。否则,在管道或重定向中没有输入时执行读取STDIN的命令将导致脚本挂起并等待STDIN输入。
其他不起作用的东西
为了解决这个问题,我研究了几种无法解决问题的技术,其中包括:
stat
[[ "${-}" =~ 'i' ]]
检查交互模式tty
和tty -s
检查tty状态[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
检查ssh
状态请注意,如果您使用的操作系统支持
/proc
虚拟文件系统,那么您可能很幸运地通过STDIO的符号链接来确定是否使用了管道。但是,/proc
不是一个跨平台、POSIX兼容的解决方案。我对解决这个问题非常感兴趣,所以如果您想到任何其他可行的技术,请告诉我,最好是在Linux和BSD上都能工作的基于POSIX的解决方案。
ny6fqffe3#
命令
test
(内置于Bash中)有一个选项来检查文件描述符是否是tty。字符串
查看“
man test
”或“man bash
”并搜索“-t
”。7bsow1i64#
你没有提到你正在使用哪个shell,但是在Bash中,你可以这样做:
字符串
7qhs6swi5#
在Solaris上,Dejay克莱顿的建议基本有效。
-p
未按预期响应。文件 bash_redir_test.sh 看起来像:
字符串
在Linux上,它工作得很好:
型
在Solaris上:
型
fykwrbwg6#
下面的代码(仅在Linux Bash 4.4中测试)* 不应被视为可移植的,也不推荐 *,但为了完整起见,这里是:
字符串
我不知道为什么,但似乎文件描述符“3”是在Bash函数具有标准输入管道时以某种方式创建的。