Obtenir la largeur de la console à l'aide d'un script bash

15

Je rencontre un problème où j'essaie d'obtenir la taille d'un terminal à l'aide de scripts. Normalement, j'utiliserais la commande tput colsà l'intérieur de la console, mais je veux pouvoir accomplir cette fonctionnalité en utilisant strictement des scripts.

À partir de maintenant, je peux détecter la console en cours d'exécution et obtenir son chemin de fichier. Cependant, j'ai du mal à utiliser ces informations pour obtenir la largeur de la console. J'ai essayé d'utiliser la commande tput, mais je suis relativement nouveau sur Linux / scripts, donc je ne sais pas vraiment quoi faire.

La raison pour cela est que je veux pouvoir configurer une entrée cron qui informe la console de sa largeur / colonnes de temps en temps.

Voici mon code jusqu'à présent:

tty.sh

#!/bin/bash

#Get PID of terminal
#terminal.txt holds most recent PID of console in use
value=$(</home/test/Documents/terminal.txt)

#Get tty using the PID from terminal.txt
TERMINAL="$(ps h -p $value -o tty)"
echo $TERMINAL

#Use tty to get full filepath for terminal in use
TERMINALPATH=/dev/$TERMINAL
echo $TERMINALPATH

COLUMNS=$(/home/test/Documents/get_columns.sh)
echo $COLUMNS

get_columns.sh

#!/usr/bin/env bash
echo $(/usr/bin/tput cols)

La sortie normale de TERMINAL& TERMINALPATHare et , par exemple &pts/terminalnumber/dev/pts/terminalnumberpts/0/dev/pts/0

sirgeezer21
la source
1
unix.stackexchange.com/questions/16578/… pourrait vous aider.
phk
@phk Je ne pense pas que cela aide. Le problème est de savoir comment indiquer au pilote tty les valeurs réelles des colonnes / lignes. Ici, il s'agit de les déterminer à partir du pilote tty.
roaima
Je ne pensais pas que les cronemplois avaient des terminaux de contrôle.
TMN

Réponses:

18

La tputcommande est un excellent outil, mais malheureusement, elle ne peut pas récupérer les paramètres réels d'un terminal sélectionné arbitrairement.

La raison en est qu'il lit stdout pour les caractéristiques du terminal, et c'est également là qu'il écrit sa réponse. Donc, au moment où vous essayez de capturer la sortie de tput colsvous, vous avez également supprimé la source de ses informations.

Heureusement, sttylit stdin plutôt que stdout pour sa détermination des caractéristiques du terminal, c'est ainsi que vous pouvez récupérer les informations de taille dont vous avez besoin:

terminal=/dev/pts/1
columns=$(stty -a <"$terminal" | grep -Po '(?<=columns )\d+')
rows=$(stty -a <"$terminal" | grep -Po '(?<=rows )\d+')

Soit dit en passant, il est inutilement lourd d'écrire ceci sous la forme echo $(/usr/bin/tput cols).

Pour toute construction que echo $(some_command)vous exécutez some_commandet capturez sa sortie, que vous passez ensuite echoà la sortie. Dans presque toutes les situations, vous pouvez imaginer que vous pourriez tout aussi bien simplement exécuter some_commandet laisser le produit directement. C'est plus efficace et aussi plus facile à lire.

roaima
la source
Quelle implémentation / version de tput/ nurses? Le mien (ncurses 6.0.20160625) fait le TIOCGWINSZ sur stderr s'il ne peut pas le faire sur stdout. cols=$(tput cols)ou cols=$(tput cols 2<> /dev/ttyx) fonctionne très bien.
Stéphane Chazelas
@ StéphaneChazelas J'ai 5.9 + 20140913-1 + b1 installé à l'origine depuis Debian "Sid". Je cherche juste une nouvelle version maintenant.
roaima
1
Fonctionne aussi bien ncurses 5.7.20100313ici. Êtes-vous certain que cols=$(tput cols 2<> /dev/tty1)cela ne fonctionne pas pour vous?
Stéphane Chazelas
@ StéphaneChazelas fascinant. Vous avez raison: si j'éloigne stdout d'un terminal, tput colslit-il depuis stderr . Je dois maintenant trouver comment réécrire ma réponse ...
roaima
1
J'utiliserais stty size <"$terminal" | read rows columnsau lieu d'essayer d'analyserstty -a
Random832
13

tput cols et tput lines interrogez la taille du terminal (à partir du pilote de périphérique du terminal, pas du terminal lui-même) à partir du périphérique terminal sur sa sortie standard, et si stdout n'est pas un périphérique terminal comme dans le cas cols=$(tput cols)où il s'agit alors d'un tuyau, de stderr.

Donc, pour récupérer les valeurs d'un périphérique terminal arbitraire, vous devez ouvrir ce périphérique sur le stderr de tput:

{ cols=$(tput cols) rows=$(tput lines); } 2< "$TERMINALPATH"

(ici ouvert en mode lecture seule, il tputne génère pas de messages d'erreur là-bas).

Vous pouvez également utiliser stty size. sttyinterroge le terminal sur stdin:

read rows cols < <(stty size < "$TERMINALPATH")

Aucun de ceux-ci n'est standard donc peut (et en pratique ne fonctionnera pas) sur tous les systèmes. Il devrait cependant être assez portable pour les systèmes GNU / Linux.

L'ajout de stty sizeou une autre méthode pour interroger la taille du terminal a été demandé à POSIX mais la discussion ne semble aller nulle part.

Stéphane Chazelas
la source
8

Ce script:

#!/bin/bash

echo "The number of columns are $COLUMNS"
echo "The number of lines are $LINES"

A travaillé ici avec absolument rien de plus .....

Pourquoi définissez-vous une variable d'environnement avec des données? COLUMNS = $ (/ home / test / Documents / get_columns.sh)

Essayez-vous d'obtenir les colonnes et les lignes d'un autre script ou tty? Est-ce que c'est ça? Toujours étrange pour moi parce que vous définissez la variable d'environnement des colonnes pour le script local ....

Luciano Andress Martini
la source
Cela n'aide pas à récupérer les valeurs dans le crontravail de l'OP pour un terminal particulier.
roaima
1
Ahn? Quelle? Maintenant, je suis plus confus, comment les scripts cronjobs peuvent-ils avoir une largeur ????? En fait, ils ne fonctionnent pas dans un terminal.
Luciano Andress Martini
Je sais. Le crontravail interroge un terminal particulier pour ses caractéristiques. (Je ne sais pas vraiment pourquoi il doit faire cela, mais c'est ce que le PO veut.)
roaima
@LucianoAndressMartini $ COLUMNS et $ LINES sont des variables bash, cela ne fonctionne pas (par exemple) dans dash et posh
ingroxd
Tks. Je sais vraiment, mais mon script est hashbang avec / bin / bash je pense qu'il est supposé que vous sachiez que vous devriez l'utiliser. Si vous utilisez un unix sans bash, peut-être que ma réponse n'est pas pour vous.
Luciano Andress Martini
1

Ma réponse est différente de celle de Roaima, car elle est dynamique. Sa / Sa réponse vous donne la taille du terminal à la création. Si vous utilisez par exemple un gestionnaire de fenêtres de mosaïque, comme i3 ou bspwm, vous préférez avoir la largeur actuelle du terminal. J'utilise donc ssty du paquet coreutils:

#!/bin/bash
stty size | awk '{print $2}'

La solution de Luciano fonctionne parfaitement dans xterm et xfce4-terminal. Je ne sais pas si tous les terminaux définissent la variable $ COLUMNS.

Sasha
la source
Ce n'est pas plus dynamique que ma réponse. Les deux vous donnent la taille du terminal au moment où vous exécutez les commandes.
roaima