la redirection stderr dans les changements de sous-shell, sortie de tput

4

Donc, je travaille sur un script et j'ai trouvé un comportement étrange. Je suis sûr qu'il existe une explication logique au fait que la sortie des 4 e et 6 e lignes de commande est différente de celle des autres cas, mais je ne parviens pas à le trouver.

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

Pourquoi la redirection stderr modifie-t-elle la sortie de tput dans un sous-shell?

Finalement, je veux faire quelque chose comme ça dans mon script pour le faire fonctionner sur des systèmes où tput / ncurses n'est pas disponible:

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

L'exemple ci-dessus a été créé avec Bash 4.3.46 (1) -release et ncurses 6.0.20150627

816-8055
la source
Je n'ai pas cela sur mon framboise, cependant, le nombre de colonnes peut être différent lorsque la sortie n'est pas interactive (comme un fichier ou / dev / null)
Archemar

Réponses:

3

Selon strace, cela se produit car tputuniquement les tentatives de lecture des paramètres tty à partir de ses sorties stdout et stderr (fd 1 et 2). Puisque vous avez explicitement redirigé stderr, et $( )redirige également stdout, tput abandonne.

La meilleure solution consisterait à appliquer une correction à tput afin de vérifier également la présence d'un terminal dans stdin ; Cependant, vous pouvez également simplement supprimer la 2>/dev/nullredirection, car tput colsne génère jamais de message d'erreur. (Et si cela produisait des messages d'erreur, mieux vaut y faire attention.)

Grawity
la source
1
Oui, ça pourrait être ça. J'ai besoin de supprimer l'erreur au cas où tput ne serait pas disponible. Comme solution de contournement, je fais ceci: if tput cols &> / dev / null; then cols = $ (tput cols) else cols = $ COLUMNS fi
816-8055