4

So I'm working on a script and found some odd behaviour. I'm sure there is a logical explanation why the output of the 4th and 6th command line is different than in the other cases, but I fail to find it.

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

Why does stderr redirection change the output of tput in a subshell?

Ultimately I want to do something like this in my script to make it work on systems where tput/ncurses isn't available:

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

The example above was created with Bash 4.3.46(1)-release and ncurses 6.0.20150627

816-8055
  • 1,327

1 Answers1

3

According to strace, this happens because tput only tries to read tty settings from its stdout and stderr (fd 1 & 2). Since you've explicitly redirected stderr, and the $( ) also redirects stdout, tput gives up.

The best fix would be to patch tput to also check stdin for presence of a tty; however, you could also just remove the 2>/dev/null redirect, since tput cols never outputs any error messages anyway. (And if it did output some error messages, it's best to pay attention to them.)

grawity
  • 501,077