Перенаправление stderr в subshell изменяет вывод tput

Поэтому я работаю над сценарием и обнаружил странное поведение. Я уверен, что есть логическое объяснение, почему выходные данные 4-й и 6-й командной строки отличаются от других случаев, но я не могу их найти.

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

Почему перенаправление stderr изменяет вывод tput в подоболочке?

В конечном итоге я хочу сделать что-то подобное в моем скрипте, чтобы он работал в системах, где tput/ncurses недоступен:

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

Пример выше был создан с использованием Bash 4.3.46(1)-релизов и ncurses 6.0.20150627

1 ответ

Решение

В соответствии с strace это происходит потому, что tput только пытается прочитать настройки tty из своих stdout и stderr (fd 1 & 2). Так как вы явно перенаправили stderr, и $( ) также перенаправляет стандартный вывод, tput сдается.

Лучшим решением было бы исправить tput, чтобы он также проверял наличие стандартного ввода в tdin; Тем не менее, вы также можете просто удалить 2>/dev/null перенаправить, так как tput cols в любом случае никогда не выводит никаких сообщений об ошибках. (И если он выводит некоторые сообщения об ошибках, лучше обратить на них внимание.)

Другие вопросы по тегам