Folgendes berücksichtigen:
me@mine:~$ cat a.sh
#!/bin/bash
echo "Lines: " $LINES
echo "Columns: " $COLUMNS
me@mine:~$ ./a.sh
Lines:
Columns:
me@mine:~$ echo "Lines: " $LINES
Lines: 52
me@mine:~$ echo "Columns: " $COLUMNS
Columns: 157
me@mine:~$
Die Variablen $LINES
und $COLUMNS
sind Shell-Variablen, keine Umgebungsvariablen, und werden daher nicht in den untergeordneten Prozess exportiert (sie werden jedoch automatisch aktualisiert, wenn ich die Größe des xterm-Fensters ändere, selbst wenn ich über ssh von einem entfernten Standort aus angemeldet bin). Gibt es eine Möglichkeit, meinem Skript die aktuelle Terminalgröße mitzuteilen?
BEARBEITEN: Ich brauche dies als Problemumgehung, um dieses Problem zu lösen : vi (sowie vim, less und ähnliche Befehle) bringt den Bildschirm jedes Mal durcheinander, wenn ich ihn benutze. Das Ändern des Terminals ist keine Option, und daher suche ich nach Problemumgehungen (das Scrollen nach unten $LINES
ist sicherlich nicht die perfekte Lösung, aber zumindest besser, als den vorherigen Bildschirm zu verlieren).
quelle
Antworten:
Sie können die Zeilen und Spalten erhalten von
tput
:#!/bin/bash lines=$(tput lines) columns=$(tput cols) echo "Lines: " $lines echo "Columns: " $columns
quelle
stty
Befehl ist in coreutils auf Cygwin enthalten, das wir anstelle von verwenden können,tput
wenn wir ncurses nicht installieren müssen. Ich habe eine Antwort mit einem Beispiel hinzugefügt.ncurses
.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 häufig keine Umgebungsvariablen. Die Shell setzt diese Werte nach jedem Befehl dynamisch und wir können normalerweise 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.$LINES
Bash setzt diese Variablen im Rahmen des Prozesses (nicht der Umgebung), wenn wir die
checkwinsize
Option aktivieren, indem wir :shopt -s checkwinsize
Viele Systeme aktivieren diese Option für uns in einer Standard- oder systemweiten Startdatei ( / etc / bashrc oder ähnlichem). Daher müssen wir uns daran erinnern, dass diese Variablen möglicherweise nicht immer verfügbar sind. Auf einigen Systemen, wie z. B. Cygwin, ist diese Option für uns nicht aktiviert, sodass Bash nicht festgelegt wird
$COLUMNS
und es$LINES
sei denn, wir führen die obige Zeile aus oder fügen sie unserem ~ / .bashrc hinzu .Tragbare Ansätze
Beim Schreiben nicht interaktiver Skripte möchten wir uns normalerweise nicht auf
$LINES
und$COLUMNS
standardmäßig verlassen (wir können diese jedoch überprüfen, damit ein Benutzer die Terminalgröße bei Bedarf manuell überschreiben kann).Stattdessen wird die
stty
undtput
bieten Dienstprogramme tragbare Mittel , um die Klemmengröße von einem Skript , um zu bestimmen (die Befehle sind nachstehend beschrieben derzeit Standardisierung für POSIX unterziehen ).Wie in der akzeptierten Antwort von Puppe gezeigt , können wir
tput
die Terminalgröße auf ziemlich einfache Weise erfassen:Alternativ gibt die
size
Abfrage fürstty
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
stty
Programm wird normalerweise mit GNU Coreutils ausgeliefert , sodass wir es häufig auf Systemen ohne finden könnentput
. Ich bevorzuge manchmal denstty
Ansatz, weil wir einen Befehl und eine Unterschale weniger aufrufen (teuer bei 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.
Nicht tragbare Ansätze
Wenn uns die Portabilität egal ist, unterstützt Bash die Prozessersetzung , 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 erstestty
Implementierung, zumindest auf meinem Computer. 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 basierend darauf, welcher Befehl auf dem Zielsystem verfügbar ist).Für Bash- Versionen 4.3 und höher können wir die
checkwinsize
Option nutzen, um eine Abhängigkeit von einem anderen Programm zu vermeiden. Wenn wir diese Option in einem Skript zu aktivieren, wird eingestellt Bash$LINES
und$COLUMNS
wie es funktioniert für eine interaktive Eingabeaufforderung nach einem Kind Prozess beendet:#!/bin/bash shopt -s checkwinsize cat /dev/null # Refresh LINES and COLUMNS
... wie wenn eine Unterschale beendet wird:
shopt -s checkwinsize (: Refresh LINES and COLUMNS)
Bash ruft die Terminalgröße nach jedem Aufruf eines externen Befehls ab, wenn wir diese Option aktivieren. Daher möchten wir sie möglicherweise nach dem Initialisieren der Variablen wieder deaktivieren:
shopt -u checkwinsize
Wenn wir aus irgendeinem Grund weiterhin
$LINES
und$COLUMNS
aus der Umgebung 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 zusammen mit der oben gezeigten Option zu .bashrc hinzucheckwinsize
. Es funktioniert gut für persönliche Skripte, aber ich empfehle nicht, diese Variablen in Skripten zu verwenden, die gemeinsam genutzt werden.quelle
size
Ausgabe zurückgesetzt. Sollte .eg seinlines=${size#* }
.size
gibt zuerst Zeilen und dann Spalten aus."%1dΔ%1d\n", <rows>, <columns>
, sodass wir uns auf die Annahme verlassen können, dass stty zuerst Zeilen und dann Spalten ausgibt. Ich werde die Antwort aktualisieren ... danke!eval $( resize )
erledigt diesen Job ... (auf einem xterm-basierten Terminal)
quelle
kill -s WINCH $$
setzt die Variablen.
quelle
Lassen Sie mich zum Abschluss erwähnen, dass das Festlegen der Option 'checkwinsize' genau das ist, wonach das OP sucht, aber es gibt einen Haken. In nicht interaktiven Skripten ist sie standardmäßig deaktiviert. Sie können jedoch die folgende Zeile am Anfang eines Skripts hinzufügen, um es zu aktivieren:
shopt -s checkwinsize
Leider werden die Variablen LINES und COLUMNS nicht sofort nach dem Festlegen der Option festgelegt (zumindest beim letzten Versuch). Stattdessen müssen Sie Bash zwingen, auf den Abschluss einer Subshell zu warten. An diesem Punkt werden diese Variablen festgelegt. Die vollständige Nur-Bash-Lösung für dieses Problem besteht darin, das Skript mit der folgenden Zeile zu starten:
shopt -s checkwinsize; (:;:)
Sie können dann die Variablen LINES und COLUMNS nach Herzenslust verwenden. Bei jeder Größenänderung des Terminals werden sie auf die richtigen Werte zurückgesetzt, ohne dass externe Dienstprogramme aufgerufen werden müssen.
quelle
Haben Sie versucht, Ihren Schebang dazu zu bringen, zu sagen:
#!/bin/bash -i
quelle
t_ti
Variablen auf null kann hilfreich seinvim
. stackoverflow.com/questions/630519/…#!/bin/bash -i
macht weder in AIX noch in Linux einen Unterschied-i
und korrekten Zahlen. Dies ist unter Ubuntu (LINES und COLUMNS werden nicht exportiert). Ich fand, dass ich auf Cygwin die beiden Variablen exportieren musste (Sie können dies in ~ / .bashrc tun), damit es funktioniert und das-i
nicht benötigt wurde. Ich musste jedochkill -SIGWINCH $$
an der Bash-Eingabeaufforderung die zu aktualisierenden Werte abrufen, wenn ich die Fenstergröße änderte (für Cygwin).-i
macht das keinen Unterschied: leere Ausgabe mit oder ohne (sowieso brauche ich diese auf AIX, nicht Ubuntu)Laufen
help export
könnte helfen?me@mine:~$ cat a.sh #!/bin/bash echo "Lines: " $LINES echo "Columns: " $COLUMNS me@mine:~$ ./a.sh Lines: Columns: me@mine:~$ echo "Lines: " $LINES Lines: 52 me@mine:~$ echo "Columns: " $COLUMNS Columns: 157 me@mine:~$ export LINES COLUMNS me@mine:~$ ./a.sh Lines: 52 Columns: 157 me@mine:~$
quelle
export LINES=$LINES
undexport COLUMNS=$COLUMNS
in meinem Bashrc, und das funktioniert richtig für mich. Sie müssen nicht haben mit tput zu verwirren.$LINES
und$COLUMNS
in bash ist nur ein Shell-y-Wrapper um die TTY-Ioctls, der Ihnen die Größe des TTY und die vom Terminal jedes Mal gesendeten Signale gibt, wenn sich diese Größe ändert.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.
EDIT: Nun, es stellt sich heraus, dass das Programm bereits existiert und aufgerufen wird
tput
. Stimmen Sie über Puppestput
Antwort ab .quelle
#!/bin/bash -i
-i
funktioniert jetzt mit bash 4.2.10 (1) -release unter 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 der Größe des Fensters. Eine Falle zeigt, dass das Skript einen SIGWINCH erhält.
quelle
Warum nicht Umgebungsvariablen für den Befehl exec wie folgt verwenden:
docker exec -ti -e LINES=$LINES -e COLUMNS=$COLUMNS container /bin/bash
quelle
Meine Erfahrung, dass Sie das Skript durch die 'starten sollten. script_to_run 'anstelle des' scritp_to_run '. Eine einfache Überprüfung wie folgt:
'(( ${#COLUMNS} )) || { echo "Try start like '. name'" ; return 1 ; }
quelle
.
Befehl wird aufgerufensource
. Nicht alle Skripte unterstützen diese Art der Ausführung. ZB wenn das Skript aufruftexit
, wird die gesamte Shell, aus der das Skript stammt, beendet, nicht nur das Skript. Siehe Was ist der Unterschied zwischensh
undsource
? .