子 shell 中的 stderr 重定向更改了 tput 的输出

子 shell 中的 stderr 重定向更改了 tput 的输出

我正在编写一个脚本,发现了一些奇怪的行为。我确信第 4行和第 6命令行的输出与其他情况不同是有逻辑解释的,但我找不到它。

1 $ tput cols
128

2 $ tput cols 2>/dev/null
128

3 $ echo $(tput cols)
128

4 $ echo $(tput cols 2>/dev/null)
80

5 $ (tput cols >/tmp/cols.txt); cat /tmp/cols.txt
128

6 $ (tput cols &>/tmp/cols.txt); cat /tmp/cols.txt
80

7 $ echo $(tput cols 2>/dev/null; echo $COLUMNS; tput cols)
80 128 128

为什么 stderr 重定向会改变子 shell 中 tput 的输出?

最终,我想在我的脚本中做这样的事情,以使其在没有 tput/ncurses 的系统上工作:

cols=$(tput cols 2>/dev/null || echo $COLUMNS)

上述示例是使用 Bash 4.3.46(1)-release 和 ncurses 6.0.20150627 创建的

答案1

根据strace,发生这种情况是因为tput仅尝试从其 stdout 和 stderr (fd 1 & 2) 读取 tty 设置。由于您已明确重定向 stderr,并且$( )也重定向 stdout,因此 tput 放弃。

最好的解决办法是修补 tput 以检查标准输入是否存在 tty;但是,您也可以删除2>/dev/null重定向,因为它tput cols无论如何都不会输出任何错误消息。(如果它确实输出了一些错误消息,最好注意它们。)

相关内容