Как мне найти ширину и высоту окна терминала?


295

В качестве простого примера я хочу написать скрипт CLI, который может печатать =по всей ширине окна терминала.

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

или

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

или

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

Я создал эту крошечную библиотеку node.js для постоянного получения правильного размера окна. Npmjs.com/package/window-size
jonschlinkert,

Ответы:


562
  • tput cols говорит вам количество столбцов.
  • tput lines говорит вам количество строк.

11
echo -e "lines\ncols"|tput -Sчтобы узнать как строки, так и столбцы, смотрите: linux.about.com/library/cmd/blcmdl1_tput.htm
nickl

4
tputотличная команда с большим количеством команд для чтения состояния терминала, управления курсором и свойствами текста и так далее.
Дрю Ноакс

2
Удобный псевдоним, например:, alias dim="echo $(tput cols)x$(tput lines)"который может привести к 80x50.
епископ

2
Эти вопросы и ответы, вероятно, относятся к сайтам SE Unix или Superuser.
mydoghasworms

2
@bishop предоставленная вами команда псевдонима оценивается при получении оболочки. Вы должны использовать одинарные кавычки для команды псевдонима. Как и так: alias dim='echo Terminal Dimensions: $(tput cols) columns x $(tput lines) rows'
brandonsimpkins

103

В bash переменные $LINESи $COLUMNSпеременные среды должны быть в состоянии добиться цели. Будет установлено автоматически при любом изменении размера терминала. (т.е. сигнал SIGWINCH )


18
Однако эти переменные среды доступны только для bash, но не для любых программ, которые работают внутри bash (например, perl, python, ruby).
Br.Bill

9
Это не работает ни в чем, кроме интерактивного сеанса bash (если вы запустите скрипт, он больше не будет интерактивным). Единственное место, где вы можете использовать его в скрипте, это prompt_command в bash.
Дончо Ганчев

1
На самом деле, он работает в неинтерактивных скриптах, если вы установите checkwinsizeопцию. Например, этот неинтерактивный скрипт напечатает размеры терминала, на котором он запущен: shopt -s checkwinsize; (:); echo $LINES $COLUMNS( checkwinsizeопция инициализирует переменные только после ожидания завершения подоболочки, поэтому нам нужен (:)оператор)
user3340662

$LINESи $COLUMNSобновляются после SIGWINCHотправки, фактически после выполнения любой интерактивной команды. Если вы пытаетесь обновить PS1с помощью, trap SIGWINCHвы не можете использовать, $LINESи $COLUMNSони сохраняют старые значения ((
gavenkoa

LINESи COLUMNSустанавливаются только как переменные оболочки bash. Bash не будет устанавливать их как переменные среды , если вы не экспортируете эти переменные оболочки.
Маркус Кун

67

И есть stty, из coreutils

$ stty size
60 120 # <= sample output

Он напечатает количество строк и столбцов или высоту и ширину соответственно.

Затем вы можете использовать либо cutили awkизвлечь часть , которую вы хотите.

Это stty size | cut -d" " -f1для высоты / линий и stty size | cut -d" " -f2для ширины / столбцов


Этот стиль не может работать с PIPE, рекомендуется использовать стиль tput.
liuyang1

6
проблема с tput заключается в том, что он не всегда доступен, тогда как stty доступен в каждом tty. спасибо за эту информацию!
ИРАС

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

3
Не прямой ответ на вопрос, а отличный демонстрационный скрипт.
Крис Пейдж

Какой отличный пример!
Курт Жонг

1
Какого черта я пропустил trкоманду все эти годы? (
лицевая сторона

Какой это язык? Это выглядит смутно как сценарий оболочки с ошибками синтаксиса. (В оболочке не должно быть пробелов вокруг знака равенства, и первая труба кажется неуместной.)
tripleee

2
yes '='выведет бесконечное количество строк '=', и следующие команды организуют достаточно для заполнения терминала
pixelbeat

12

Чтобы сделать это в среде Windows CLI, лучший способ, который я могу найти, - это использовать команду mode и проанализировать вывод.

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;
}

Я надеюсь, что это полезно!

ПРИМЕЧАНИЕ . Возвращаемая высота - это количество строк в буфере, а не количество строк, видимых в окне. Есть ли лучшие варианты там?


3
Обратите внимание на проблему с этим: выходные данные этой команды зависят от локали. Другими словами, это не будет работать как есть на другом языке Windows. Вот что я получаю в Windows 7: i.imgur.com/Wrr7sWY.png
Камило Мартин

Добавил ответ с решением для этого. +1 хотя!
Камило Мартин

10

В POSIX, в конечном счете, вы хотите вызвать TIOCGWINSZ(Get WINdow SiZe) ioctl()вызов. У большинства языков должна быть какая-то обертка для этого. Например, в Perl вы можете использовать термин :: размер :

use Term::Size qw( chars );

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

1
Спасибо за это - привел меня в правильном направлении. Эликсир: :io.columnsЭрланг: io:columns(). erlang.org/doc/man/io.html#columns-0
Хенрик N

2
В TIOCGWINSZстандарте POSIX его нет, и ioctl()он определен только для устаревшей функции STREAMS.
17

4

Как я уже упоминал в ответе лицея, его код не будет работать в неанглийской локали Windows, потому что тогда выходные данные modeмогут не содержать подстрок «столбцы» или «строки»:

                                         вывод команды mode

Вы можете найти правильную подстроку без поиска текста:

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

Обратите внимание, что я даже не беспокоюсь о строках, потому что они ненадежны (и я на самом деле их не волную).

Изменить: Согласно комментариям о Windows 8 (о, вы ...), я думаю, что это может быть более надежным:

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

Проверьте это, хотя, потому что я не проверял это.


Ваш метод не работает в Win8. Я получаю более одной ---строки. i.imgur.com/4x02dqT.png
mpen

@ Марк Ну, отлично, это просто КРАСИВО. Спасибо винде. <3 (более уместно: я посмотрю, как это исправить ... когда выйдет Windows 9: P).
Камило Мартин

Вот как я это делаю $mode = `mode`; list($rows, $cols) = array_slice(preg_split('/\n/', substr($mode, strpos($mode, 'CON:'))), 2, 2);. И тогда я просто заменяю все, кроме цифр.
Александр Маков

@AleksandrMakov Интересно, что будет, если есть языки с порядком вроде CON device status:? Может быть, что-то похожееCON.*: будет работать лучше.
Камило Мартин

1
@ Марк, я на самом деле расспрашивал себя именно об этом. Какого черта я это сделал? В сомнении, я просто предположил, что была какая-то причина, и пошел с этим, смеется.
Камило Мартин

1

Вдохновленный ответом @ pixelbeat, вот горизонтальная полоса, появившаяся благодаря tputнебольшому неправильному использованию printfотступов / заливки иtr

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

0

В некоторых случаях ваши строки / строки и столбцы не соответствуют фактическому размеру используемого «терминала». Возможно, у вас нет доступных «tput» или «stty».

Вот функция bash, которую вы можете использовать для визуальной проверки размера. Это будет работать до 140 столбцов х 80 строк. Вы можете настроить максимумы по мере необходимости.

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"
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.