好奇的tput行为,带有stderr重定向

时间:2014-02-13 19:11:31

标签: bash io-redirection

我正在尝试在Bash脚本中使用tput,并尽力避免随机错误。为此,我写了以下这一行:

COLS="$(tput cols 2> /dev/null)"

令我惊讶的是,当我运行它时,COLS始终设置为80,无论我的终端窗口的宽度是多少。 (为了演示,我的终端恰好是115列宽。)为了弄清楚发生了什么,我在命令行上尝试了一些事情:

$ tput cols
115
$ tput cols | cat
115
$ echo "$(tput cols)"
115
$ tput cols 2> /dev/null
115
$ echo "$(tput cols 2> /dev/null)"
80

因此,tput似乎成功地在重定向stderr时确定终端特性,或者当它嵌入在进程替换中时,但不是两者都有。多奇怪啊!

我在Linux和OS X上测试了这个,行为是一样的。

这里发生了什么?实际上,在抑制stderr喷射的同时让tput工作的最佳方法是什么?

注意:我知道$COLUMNS。我特别感兴趣的是使用tput

2 个答案:

答案 0 :(得分:5)

快速strace运行表明tput首先尝试确定stdout上的终端宽度,如果失败,则会回退到stderr。因此,在失败的情况下,两者都被重定向,并且tput(显然)假设默认值为80列。

答案 1 :(得分:0)

由于我遇到了类似的问题,谷歌把我带到了这里。事实上,虽然接受的答案确实回答了问题,但它并没有提供任何关于如何解决原始问题中提到的错误喷射的建议。我以为可以解决这个问题。

我的具体情况是编写可以从命令行或从cron调用的脚本。从cron运行时,Solaris将TERM变量设置为" dumb",tput对此一无所知,并且它会发出错误(将邮件发送给所有者的cron工作)。由于您无法捕获错误并且stdout要获取列数,因此我首先尝试找出一种方法来确定tput是否知道特定终端,然后再运行tput cols。为此,这段代码似乎符合我的目的:

declare TPUT C
TPUT="$(tput longname 2>/dev/null)"
[[ "$TPUT" ]] && C="$(tput cols)"
C=${C:-80}

我意识到这并没有抓住所有错误,但如果tput不了解某个特定终端,它至少可以避免错误。