Wie finde ich die Breite und Höhe eines Terminalfensters?


295

Als einfaches Beispiel möchte ich ein CLI-Skript schreiben, das =über die gesamte Breite des Terminalfensters gedruckt werden kann .

#!/usr/bin/env php
<?php
echo str_repeat('=', ???);

oder

#!/usr/bin/env python
print '=' * ???

oder

#!/usr/bin/env bash
x=0
while [ $x -lt ??? ]; do echo -n '='; let x=$x+1 done; echo

Ich habe diese winzige node.js lib erstellt, um konsistent die richtige Fenstergröße zu erhalten. Npmjs.com/package/window-size
jonschlinkert

Antworten:


562
  • tput cols gibt Ihnen die Anzahl der Spalten an.
  • tput lines gibt Ihnen die Anzahl der Zeilen an.

11
echo -e "lines\ncols"|tput -SUm sowohl die Zeilen als auch die Spalten
nickl

4
tputist ein großartiger Befehl mit vielen Befehlen zum Lesen des Status des Terminals, zum Steuern der Cursor- und Texteigenschaften usw.
Drew Noakes

2
Praktischer Alias ​​zum Beispiel : alias dim="echo $(tput cols)x$(tput lines)", der dazu führen kann 80x50.
Bischof

2
Diese Fragen und Antworten gehören wahrscheinlich entweder zu den Unix- oder Superuser SE-Sites.
Mydoghaswürmer

2
@bishop Der von Ihnen angegebene Alias-Befehl wird ausgewertet, wenn die Shell bezogen wird. Sie müssen einfache Anführungszeichen für den Alias-Befehl verwenden. Wie so: alias dim='echo Terminal Dimensions: $(tput cols) columns x $(tput lines) rows'
brandonsimpkins

103

In Bash sollten die $LINESund $COLUMNSUmgebungsvariablen in der Lage sein, den Trick auszuführen. Das wird bei jeder Änderung der Terminalgröße automatisch eingestellt. (dh das SIGWINCH- Signal)


18
Diese Umgebungsvariablen sind jedoch nur für Bash verfügbar und nicht für Programme, die in Bash ausgeführt werden (wie Perl, Python, Ruby).
Br.Bill

9
Das funktioniert nur in der interaktiven Bash-Sitzung (wenn Sie das Skript ausführen, ist es nicht mehr interaktiv). Der einzige Ort, an dem Sie es in einem Skript verwenden können, ist der prompt_command in bash.
Doncho Gunchev

1
Tatsächlich funktioniert es in nicht interaktiven Skripten, wenn Sie die checkwinsizeOption festlegen . Dieses nicht interaktive Skript druckt beispielsweise die Abmessungen des Terminals, auf dem es ausgeführt wird: shopt -s checkwinsize; (:); echo $LINES $COLUMNS(Die checkwinsizeOption initialisiert die Variablen erst, nachdem auf das Ende einer Subshell gewartet wurde, weshalb wir die (:)Anweisung benötigen. )
user3340662

$LINESund $COLUMNSwerden nach dem SIGWINCHSenden aktualisiert , tatsächlich nach jeder interaktiven Befehlsausführung. Wenn Sie zu aktualisieren versuchen , PS1mit trap SIGWINCHIhnen nicht verwenden können $LINESund $COLUMNShalten sie alte Werte ((
gavenkoa

LINESund COLUMNSwerden nur von bash als Shell-Variablen gesetzt. Bash legt sie nicht als Umgebungsvariablen fest , es sei denn, Sie exportieren diese Shell-Variablen.
Markus Kuhn

67

Und es gibt sttyvon Coreutils

$ stty size
60 120 # <= sample output

Es wird die Anzahl der Zeilen und Spalten bzw. die Höhe und Breite gedruckt.

Dann können Sie entweder cutoder verwenden awk, um das gewünschte Teil zu extrahieren.

Das ist stty size | cut -d" " -f1für die Höhe / Linien und stty size | cut -d" " -f2für die Breite / Spalten


Dieser Stil funktioniert nicht mit PIPE. Schlagen Sie die Verwendung des Eingabestils vor.
Liuyang1

6
Das Problem mit tput ist, dass es nicht immer verfügbar ist, während stty in jedem tty verfügbar ist. danke für diese info!
iRaS

16
yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'

3
Keine direkte Antwort auf die Frage, sondern ein großartiges Demo-Skript.
Chris Seite

Was für ein großartiges Beispiel!
Kurt Zhong

1
Wie zum Teufel habe ich das trKommando all die Jahre verpasst ? (Gesichtspalme)
Marco Massenzio

Welche Sprache ist das? Es sieht vage aus wie ein Shell-Skript mit Syntaxfehlern. (In der Shell können Sie keine Leerzeichen um das Gleichheitszeichen der Zuweisung haben, und die erste Pipe scheint fehl am Platz zu sein.)
Tripleee

2
yes '='gibt unendlich viele '=' Zeilen aus und die folgenden Befehle sind so organisiert, dass sie das Terminal füllen
pixelbeat

12

Um dies in einer Windows CLI-Umgebung zu tun, kann ich am besten den Befehl mode verwenden und die Ausgabe analysieren.

function getTerminalSizeOnWindows() {
  $output = array();
  $size = array('width'=>0,'height'=>0);
  exec('mode',$output);
  foreach($output as $line) {
    $matches = array();
    $w = preg_match('/^\s*columns\:?\s*(\d+)\s*$/i',$line,$matches);
    if($w) {
      $size['width'] = intval($matches[1]);
    } else {
      $h = preg_match('/^\s*lines\:?\s*(\d+)\s*$/i',$line,$matches);
      if($h) {
        $size['height'] = intval($matches[1]);
      }
    }
    if($size['width'] AND $size['height']) {
      break;
    }
  }
  return $size;
}

Ich hoffe es ist nützlich!

HINWEIS : Die zurückgegebene Höhe ist die Anzahl der Zeilen im Puffer. Es ist nicht die Anzahl der Zeilen, die im Fenster sichtbar sind. Gibt es bessere Möglichkeiten da draußen?


3
Beachten Sie ein Problem damit: Die Ausgabe dieses Befehls ist länderspezifisch. Mit anderen Worten, dies funktioniert nicht wie es ist in einem anderen Windows-Gebietsschema. Dies ist, was ich unter Windows 7 bekomme
Camilo Martin

Eine Antwort mit einer Lösung wurde hinzugefügt. +1 obwohl!
Camilo Martin

10

Unter POSIX möchten Sie letztendlich den Aufruf TIOCGWINSZ(Get WINdow SiZe) ioctl()aufrufen. Die meisten Sprachen sollten dafür eine Art Wrapper haben. In Perl können Sie beispielsweise Term :: Size verwenden :

use Term::Size qw( chars );

my ( $columns, $rows ) = chars \*STDOUT;

1
Danke dafür - hat mich in die richtige Richtung geführt. Elixier: :io.columnsErlang: io:columns(). erlang.org/doc/man/io.html#columns-0
Henrik N

2
Der TIOCGWINSZPOSIX-Standard enthält keine und ioctl()ist nur für die veraltete STREAMS-Funktion definiert.
Osvein

4

Wie ich in der Antwort von lyceus erwähnt habe, schlägt sein Code unter nicht-englischen Windows-Gebietsschemas fehl, da die Ausgabe von modemöglicherweise nicht die Teilzeichenfolgen "Spalten" oder "Zeilen" enthält:

                                         Ausgabe des Modusbefehls

Sie können den richtigen Teilstring finden, ohne nach Text zu suchen:

 preg_match('/---+(\n[^|]+?){2}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Beachten Sie, dass ich mich nicht einmal mit Zeilen beschäftige, weil sie unzuverlässig sind (und sie mir eigentlich egal sind).

Bearbeiten: Laut Kommentaren zu Windows 8 (oh du ...) denke ich, dass dies zuverlässiger sein kann:

 preg_match('/CON.*:(\n[^|]+?){3}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Testen Sie es trotzdem, weil ich es nicht getestet habe.


Ihre Methode funktioniert in Win8 nicht. Ich bekomme mehr als eine ---Zeile. i.imgur.com/4x02dqT.png
mpen

@ Mark Nun, toll, das ist einfach wunderschön. Vielen Dank, dass Sie Windows. <3 (in einem relevanteren Hinweis: Ich werde sehen, wie das behoben werden kann ... wenn Windows 9 herauskommt: P).
Camilo Martin

So mache ich das : $mode = `mode`; list($rows, $cols) = array_slice(preg_split('/\n/', substr($mode, strpos($mode, 'CON:'))), 2, 2);. Und dann ersetze ich einfach alles außer Zahlen.
Aleksandr Makov

@AleksandrMakov Ich frage mich, was passiert, wenn es Sprachen mit einer Reihenfolge wie gibt CON device status:? Vielleicht CON.*:würde es besser funktionieren, so etwas zusammenzubringen .
Camilo Martin

1
@ Mark Ich habe mich genau das gefragt. Warum zum Teufel habe ich das getan? Im Zweifel nahm ich nur an, dass es einen Grund gab und ging damit einher, lol.
Camilo Martin

1

Inspiriert von der Antwort von @ pixelbeat, ist hier ein horizontaler Balken, der durch tputleichten Missbrauch von printfPolsterung / Füllung und entstanden isttr

printf "%0$(tput cols)d" 0|tr '0' '='

0

In einigen Fällen stimmen Ihre Zeilen / Zeilen und Spalten nicht mit der tatsächlichen Größe des verwendeten "Terminals" überein. Möglicherweise steht Ihnen kein "tput" oder "stty" zur Verfügung.

Hier ist eine Bash-Funktion, mit der Sie die Größe visuell überprüfen können. Dies funktioniert bis zu 140 Spalten x 80 Zeilen. Sie können die Maxima nach Bedarf anpassen.

function term_size
{
    local i=0 digits='' tens_fmt='' tens_args=()
    for i in {80..8}
    do
        echo $i $(( i - 2 ))
    done
    echo "If columns below wrap, LINES is first number in highest line above,"
    echo "If truncated, LINES is second number."
    for i in {1..14}
    do
        digits="${digits}1234567890"
        tens_fmt="${tens_fmt}%10d"
        tens_args=("${tens_args[@]}" $i)
    done
    printf "$tens_fmt\n" "${tens_args[@]}"
    echo "$digits"
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.