I'm trying to get the width of the current terminal window in a script and use 80 as a fallback in case that isn't possible. I thought that's pretty simple:
cols=$( tput cols || echo 80 ) ; echo $cols
# -> 100
100 is correct, I made the terminal 100 chars wide. As cols
is no POSIX conform argument to tput
, not all systems will support it, thus the fallback. Now let's test the fallback:
cols=$( tput colsx || echo 80 ) ; echo $cols
# -> tput: unknown terminfo capability 'colsx'
# -> 80
Hmmmm... not so nice. I don't want to see that error. It's printed on stderr
, so let's just suppress it:
cols=$( tput colsx 2>/dev/null || echo 80 ) ; echo $cols
# -> 80
Yes, that's much better. So the final code is
cols=$( tput cols 2>/dev/null || echo 80 ) ; echo $cols
# -> 80
80? WTF? Why does it run into the fallback now? Let's try this:
cols=$( tput cols 2>/dev/null ) ; echo $cols
# -> 80
Ahhhh... redirecting stderr
changes the output of tput
? How's that possible? Let's confirm that:
tput cols 2>/dev/null
# -> 100
Okay, now I'm lost! Can someone please explain me what's going on here?
There's a partial answer here
tput cols
can lead to data from different sources based on these cases:
When running tput cols
: terminal setting columns
may be fetched
with an ioctl()
using fd 1,2 if possible, otherwise get terminfo
capability cols
.
This session sets 99 for terminal columns,
$ stty columns 99; stty -a | grep columns
speed 38400 baud; rows 24; columns 99; line = 0;
Only fd 1 redirected (to a non-tty):
$ tput cols > out; cat out
99
Only fd 2 redirected:
$ tput cols 2> err; wc -c err
99
0 err
Both fd 1,2 redirected:
$ tput cols > out 2>&1; cat out
80
fd 1 not a tty:
$ echo $(tput cols || echo 100)
99
fd 1,2 not a tty:
$ echo $(tput cols 2> /dev/null || echo 100)
80
To show cols
cabability being fetched when fd 1,2 are redirected,
a terminfo named tmp
with different cols
was created and installed, then:
$ export TERM=tmp TERMINFO=$HOME/.ti
$ infocmp | grep cols
colors#8, cols#132, it#8, lines#24, pairs#64,
fd 1,2 not a tty:
$ echo $(tput cols 2> /dev/null || echo 100)
132
fake cap, tput exits non-zero:
$ echo $(tput kol 2> /dev/null || echo 100)
100