Подтвердить что ты не робот

LINES и COLUMNS переменные среды, потерянные в script

Рассмотрим следующее:

[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]:~$ 

Переменные $LINES и $COLUMNS являются переменными оболочки, не переменными окружения и, следовательно, не экспортируются в дочерний процесс (но они автоматически обновляются, когда я изменяю размер окна xterm, даже при входе в систему через ssh из удаленного места). Есть ли способ, позволяющий моему script узнать текущий размер терминала?

EDIT: Мне нужно это в качестве решения этой проблемы: vi (а также vim, less и подобные команды) каждый раз испортит экран каждый раз, когда я его использую. Изменение терминала не является вариантом, и поэтому я ищу обходные пути (прокрутка вниз $LINES строк, безусловно, не идеальное решение, но по крайней мере лучше, чем потерять предыдущий экран)

4b9b3361

Ответ 1

Вы можете получить строки и столбцы от tput:

#!/bin/bash

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

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

Ответ 2

kill -s WINCH $$

устанавливает переменные.

Ответ 3

eval $( resize )

выполняет эту работу... (на терминале на основе xterm)

Ответ 4

Попробовали ли вы заставить свой shebang сказать:

#!/bin/bash -i

Ответ 6

$LINES и $COLUMNS в bash - это всего лишь оболочка-оболочка вокруг TTY ioctls, дающая вам размер TTY и сигналы, посылаемые терминалом каждый раз, когда этот размер изменяется.

Вы можете написать программу на другом языке, который вызывает эти ioctls напрямую, чтобы получить размеры TTY, а затем использовать эту программу.

EDIT: Ну, оказывается, что программа уже существует и называется tput. Голосовать Puppe tput на основе ответа.

Ответ 7

#!/bin/bash -i

-i теперь работает с bash 4.2.10 (1) -release на 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.

Числа изменяются с изменением размера окна; ловушка показывает, что script получает SIGWINCH.

Ответ 8

Поскольку этот вопрос популярен, я хочу добавить более новый ответ с дополнительной информацией.

Переменные $COLUMNS и $LINES не являются переменными среды. Эти значения динамически устанавливаются оболочкой после каждой команды, и мы обычно не можем получить к ней доступ из неинтерактивных скриптов.

Bash устанавливает эти переменные, когда мы включаем параметр checkwinsize, используя:

shopt -s checkwinsize 

Во многих системах этот параметр используется для файла по умолчанию или для всего системного файла (bashrc), поэтому нам нужно помнить, что эти переменные могут быть недоступны. В некоторых системах, таких как Cygwin, эта опция не включена для нас, поэтому Bash не устанавливает $COLUMNS и $LINES, если мы не выполним строку выше или не добавим ее в наш .bashrc.


При написании неинтерактивных скриптов мы не можем использовать $LINES и $COLUMNS по умолчанию. Вместо этого утилиты stty и tput предоставляют переносные средства для определения размера терминала из script (ниже описаны команды которые в настоящее время проходят стандартизацию для POSIX).

Как показано в текущем принятом ответе, мы можем использовать tput, чтобы собрать размер терминала довольно просто:

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

В качестве альтернативы запрос size для stty дает нам количество строк и столбцов терминала за один шаг (выводится как число столбцов, за которыми следуют два пробела, за которыми следует количество строк):

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

Я иногда предпочитаю подход stty, потому что мы вызываем еще одну команду и подоболочку (дорогостоящую на Cygwin), но она требует, чтобы мы анализировали вывод в строках и столбцах, что может быть менее читаемым:

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

Оба подхода, описанные выше, работают в любой оболочке POSIX. Для Bash в частности, мы можем использовать замещение процесса, чтобы упростить предыдущий пример:

read columns lines < <(stty size) 

... который работает быстрее, чем пример tput, но все же медленнее, чем первая реализация stty, по крайней мере, на моей машине. На практике влияние производительности, вероятно, незначительно - выберите подход, который лучше всего подходит для программы (или на основе того, какая команда доступна в целевой системе).


Если по каким-то причинам мы хотим использовать $LINES и $COLUMNS в наших сценариях, мы можем настроить Bash для экспорта этих переменных в среду:

trap 'export LINES COLUMNS' DEBUG

Ловушка DEBUG выполняется перед каждой командой, введенной в приглашении, поэтому мы можем использовать ее для экспорта этих переменных. Посредством повторного экспорта их после каждой команды мы гарантируем, что переменные среды будут обновлены, если размер терминала изменится. Добавьте эту строку в .bashrc. Он отлично работает для личных скриптов, но я не рекомендую использовать эти переменные в любом script, который будет использоваться совместно.