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,176
  • 1
  • 8
  • 12
  • I don't have this on my rapsberry, however, number of column might be different when output is non interactive (like a file or /dev/null ) – Archemar Oct 15 '16 at 09:18

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.)

u1686_grawity
  • 426,297
  • 64
  • 894
  • 966
  • 1
    Yes, that might be it. I need to suppress the error in case tput isn't available. As a workaround I'm doing this: if tput cols &>/dev/null; then cols=$(tput cols) else cols=$COLUMNS fi – 816-8055 Oct 15 '16 at 14:29