it-swarm.com.de

LINES und COLUMNS Umgebungsvariablen in einem Skript verloren

Folgendes berücksichtigen:

[email protected]:~$ cat a.sh 
#!/bin/bash
echo "Lines: " $LINES
echo "Columns: " $COLUMNS
[email protected]:~$ ./a.sh 
Lines: 
Columns: 
[email protected]:~$ echo "Lines: " $LINES
Lines:  52
[email protected]:~$ echo "Columns: " $COLUMNS
Columns:  157
[email protected]:~$ 

Die Variablen $LINES und $COLUMNS sind Shell-Variablen, nicht Umgebungsvariablen, und werden daher nicht in den untergeordneten Prozess exportiert (sie werden jedoch automatisch aktualisiert, wenn ich die Größe des Xterm-Fensters verkleinere, selbst wenn ich von einem entfernten Standort aus über ssh angemeldet bin.) . Gibt es eine Möglichkeit, meinem Skript die aktuelle Terminalgröße mitzuteilen?

EDIT: Ich brauche das als Workaround. Wenn dieses Problem : vi (sowie vim, less und ähnliche Befehle) den Bildschirm jedes Mal durcheinander bringt, wenn ich es benutze. Das Ändern des Terminals ist keine Option, und daher suche ich nach Abhilfemaßnahmen (das Scrollen nach unten $LINES Zeilen ist sicherlich nicht die perfekte Lösung, aber zumindest besser als der Verlust des vorherigen Bildschirms.)

56
Davide

Sie können die Zeilen und Spalten von tput erhalten:

#!/bin/bash

lines=$(tput lines)
columns=$(tput cols)

echo "Lines: " $lines
echo "Columns: " $columns
74
Puppe

Da diese Frage sehr beliebt ist, möchte ich eine neuere Antwort mit einigen zusätzlichen Informationen hinzufügen.

In modernen Systemen sind die Variablen $COLUMNS Und $LINES Häufig keine Umgebungsvariablen. Die Shell legt diese Werte nach jedem Befehl dynamisch fest und normalerweise können wir nicht über nicht interaktive Skripte darauf zugreifen. Einige Programme respektieren diese Werte, wenn wir sie exportieren , aber dieses Verhalten ist nicht standardisiert oder wird nicht allgemein unterstützt.

Bash setzt diese Variablen im Rahmen des Prozesses (nicht in der Umgebung), wenn wir die Option checkwinsize aktivieren mit:

shopt -s checkwinsize 

Viele Systeme aktivieren diese Option für uns in einer standardmäßigen oder systemweiten Startdatei (/ etc/bashrc oder ähnliches), daher müssen wir uns daran erinnern, dass diese Variablen möglicherweise nicht immer verfügbar sind. Auf einigen Systemen wie Cygwin ist diese Option für uns nicht aktiviert, daher setzt Bash nicht $COLUMNS Und $LINES, Es sei denn, wir führen die obige Zeile aus oder fügen sie unserer hinzu ~/.bashrc.


Wenn wir nicht interaktive Skripte schreiben, möchten wir uns normalerweise nicht standardmäßig auf $LINES Und $COLUMNS Verlassen (aber wir können Aktivieren Sie diese Kontrollkästchen, damit ein Benutzer die Terminalgröße bei Bedarf manuell überschreiben kann.

Stattdessen bieten die Dienstprogramme stty und tput portable Möglichkeiten, die Terminalgröße anhand eines Skripts zu bestimmen (die beschriebenen Befehle) Nachfolgend finden Sie wird derzeit für POSIX standardisiert ).

Wie in der akzeptierten Antwort von Puppe gezeigt, können wir tput verwenden, um die Terminalgröße auf ziemlich einfache Weise zu ermitteln:

lines=$(tput lines)
columns=$(tput cols)

Alternativ gibt die Abfrage size für stty die Anzahl der Terminalzeilen und -spalten in einem Schritt an (Ausgabe als Anzahl der Zeilen, gefolgt von zwei Leerzeichen, gefolgt von der Anzahl der Spalten):

size=$(stty size)  # "40  80" for example 

Das Programm stty wird normalerweise mit GNU Coreutils ausgeliefert, so dass wir es häufig auf Systemen ohne tput finden können. Ich bevorzuge manchmal den stty -Ansatz, weil wir einen Befehl und eine Subshell weniger aufrufen (teuer für Cygwin), aber es erfordert, dass wir die Ausgabe in Zeilen und Spalten analysieren, die möglicherweise weniger lesbar sind:

lines=${size% *}
columns=${size#* }

Beide oben beschriebenen Ansätze funktionieren in jeder POSIX-Shell. Insbesondere für Bash können wir die Prozessersetzung verwenden, um das vorherige Beispiel zu vereinfachen:

read lines columns < <(stty size) 

... was schneller läuft als das tput Beispiel, aber immer noch langsamer als die erste stty Implementierung, zumindest auf meinem Rechner. In der Praxis ist die Auswirkung auf die Leistung wahrscheinlich vernachlässigbar - wählen Sie den Ansatz, der für das Programm am besten geeignet ist (oder auf der Grundlage, welcher Befehl auf dem Zielsystem verfügbar ist).


Wenn wir aus irgendeinem Grund immer noch $LINES Und $COLUMNS In unseren Skripten verwenden möchten, können wir Bash so konfigurieren, dass diese Variablen in die Umgebung exportiert werden:

trap 'export LINES COLUMNS' DEBUG

Der Bash DEBUG Trap wird vor jedem an der Eingabeaufforderung eingegebenen Befehl ausgeführt, sodass wir ihn zum Exportieren dieser Variablen verwenden können. Durch erneutes Exportieren mit jedem Befehl stellen wir sicher, dass die Umgebungsvariablen auf dem neuesten Stand bleiben, wenn sich die Terminalgröße ändert. Fügen Sie diese Zeile zu .bashrc zusammen mit der oben gezeigten Option checkwinsize. Es funktioniert gut für persönliche Skripte, aber ich empfehle nicht, diese Variablen in Skripten zu verwenden, die gemeinsam genutzt werden.

20
Cy Rossignol
eval $( resize )

macht diesen Job ... (auf einem Xterm-basierten Terminal)

6
Anthony
kill -s WINCH $$

setzt die Variablen.

5
elo

Zum Abschluss möchte ich erwähnen, dass das Setzen der Option 'checkwinsize' genau das ist, wonach das OP sucht, aber es gibt einen Haken. In nicht interaktiven Skripten ist diese Einstellung standardmäßig nicht festgelegt. Sie können jedoch die folgende Zeile am Anfang eines Skripts hinzufügen, um sie zu aktivieren:

shopt -s checkwinsize

Leider werden die Variablen LINES und COLUMNS nicht sofort beim Setzen der Option gesetzt (zumindest beim letzten Versuch). Stattdessen müssen Sie Bash zwingen, zu warten, bis eine Subshell abgeschlossen ist. Dann werden diese Variablen gesetzt. Die vollständige Bash-Only-Lösung für dieses Problem besteht darin, Ihr Skript mit der folgenden Zeile zu starten: 

shopt -s checkwinsize; (:;:)

Sie können dann die Variablen LINES und COLUMNS nach Herzenslust verwenden. Sie werden bei jeder Größenänderung des Terminals auf die korrekten Werte zurückgesetzt, ohne dass externe Dienstprogramme aufgerufen werden müssen.

3
Marc Coiffier

Das Ausführen von help export könnte helfen?

[email protected]:~$ cat a.sh 
#!/bin/bash
echo "Lines: " $LINES
echo "Columns: " $COLUMNS
[email protected]:~$ ./a.sh 
Lines: 
Columns: 
[email protected]:~$ echo "Lines: " $LINES
Lines:  52
[email protected]:~$ echo "Columns: " $COLUMNS
Columns:  157
[email protected]:~$ export LINES COLUMNS
[email protected]:~$ ./a.sh 
Lines:  52
Columns:  157
[email protected]:~$ 
2
SwordFish

Haben Sie versucht, Ihren Shebang dazu zu bringen, zu sagen:

#!/bin/bash -i
2

$LINES und $COLUMNS in bash ist nur ein Shell-y-Wrapper um die TTY-Ioctls, der die Größe des TTY und die vom Terminal gesendeten Signale bei jeder Änderung dieser Größe angibt.

Sie könnten ein Programm in einer anderen Sprache schreiben, das diese ioctls direkt aufruft, um zu den TTY-Dimensionen zu gelangen, und dann dieses Programm verwenden.

BEARBEITEN: Nun, es stellt sich heraus, dass das Programm bereits existiert und heißt tput. Stimmen Sie ab Puppe tput basierte Antwort .

1
ndim
#!/bin/bash -i

-i arbeitet jetzt mit bash 4.2.10 (1) - release on Ubuntu 11.10 .

$ cat show_dimensions.sh 
#!/bin/bash -i
printf "COLUMNS = %d\n" $COLUMNS
printf "LINES = %d\n" $LINES

$ ./show_dimensions.sh 
COLUMNS = 150
LINES = 101

$ bash --version
GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Die Zahlen ändern sich mit einer Fenstergröße. Eine Falle zeigt, dass das Skript ein SIGWINCH bekommt.

1
Seganku

Warum verwenden Sie Umgebungsvariablen nicht im exec-Befehl wie folgt:

docker exec -ti -e LINES=$LINES -e COLUMNS=$COLUMNS  container /bin/bash
0
Classsic