我正在尝试在 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
似乎成功地弄清楚了当它的stdrr被重定向时,或者当它被嵌入到进程替换中时,而不是两者兼而有之。真奇怪!
我在 Linux 和 OS X 上都对此进行了测试,行为是相同的。
这是怎么回事?实际上,在抑制标准喷出的同时让tput
工作的最佳方法是什么?
注意:我知道$COLUMNS
.我对使用tput
特别感兴趣。
快速strace
运行表明tput
首先尝试确定stdout
上的端子宽度,如果失败,它将回退到stderr
。因此,在失败的情况下,两者都被重定向,并且tput
(显然)假设默认值为 80 列。
谷歌把我带到这里,因为我遇到了类似的问题。 虽然接受的答案实际上确实回答了这个问题,但它并没有真正提供任何关于如何解决原始问题中提到的错误的建议。 以为我会插话一个可能的解决方法。
我的具体情况是编写可以从命令行或 cron 调用的脚本。 从 cron 运行时,Solaris 将 TERM
变量设置为"dumb",tput
对此一无所知,并且会引发错误(这些错误会邮寄给 cron 作业的所有者)。 由于您无法捕获错误和 stdout 来获取列数,因此在运行 tput cols
之前,我首先尝试找出一种方法来确定 tput 是否知道特定终端。 为此,这段代码似乎符合我的目的:
declare TPUT C
TPUT="$(tput longname 2>/dev/null)"
[[ "$TPUT" ]] && C="$(tput cols)"
C=${C:-80}
我意识到这不会捕获所有错误,但如果tput
不知道特定终端,它至少会避开可能的错误。
显然他们此后改变了tput
。它在 Ubuntu 18.04 中效果更好(ncurses 6.2.20200212)。即使使用较旧的软件运行eval $(resize)
,tput
命令也可能有所帮助,但您必须为此安装 xterm。有关tput
方法的替代方案,请参阅此处。