shell 管道中的命令能否确定其上下文的 tty 特征?

Ras*_*att 1 shell pipe io-redirection shell-script stty

我有一个 bash 脚本,可以对项目列表进行列化。默认情况下,它会根据报告的终端宽度猜测要输出的列数stty size。但是当脚本在管道中时,stty报告“设备的 ioctl 不合适”。

我想要的是允许我的脚本在作为管道中间的命令执行时,发现它所属的管道是否最终输出到 tty - 如果是,则能够确定其特征。

解决方案:正如下面所指出的,stty -F /dev/tty似乎可以在管道中的任何地方工作。

Ste*_*itt 6

您可以使用脚本进行尝试,例如

#!/bin/sh

for fd in 0 1 2; do
    if [ -t $fd ]; then echo $fd is a TTY; fi
done
Run Code Online (Sandbox Code Playgroud)

运行这个我看到:

  • 如果脚本自行运行,则所有三个 FD 都是 TTY
  • 如果脚本在管道开始时运行,stdin并且stderr是 TTY
  • 如果脚本在管道中间运行,stderr则为 TTY
  • 如果脚本在管道末端运行,stdout并且stderr是 TTY

这一切似乎合乎逻辑。显然,如果管道也重定向stderr,行为就会不同。

为了完整回答您的问题,我认为不可能在所有情况下都确定终端特征,但是如果您能找到一个 FD(检查 中的所有条目/dev/fd),它是一个 TTY,您可以在其stty上运行...但是不可能从管道的中间确定管道末端的去向。

正如Janis所提到的,如果您想了解有关控制终端的信息,无论管道如何,您都可以使用/dev/tty例如with stty -F /dev/tty; 但是如果脚本在没有控制终端的情况下运行,例如cron作业中运行,那将会失败。