LINES和COLUMNS环境变量在脚本中丢失

时间:2009-11-23 00:01:06

标签: bash shell terminal environment-variables

请考虑以下事项:

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

变量$LINES$COLUMNS是shell变量,不是环境变量,因此不会导出到子进程(但是当我调整大小时,它们会自动更新xterm窗口,即使从远程位置通过ssh登录也是如此)。有没有办法让我的脚本知道当前的终端大小?

编辑: 我需要这个作为解决方法做this problem:vi(以及vim,less和类似命令)每次使用它时都会弄乱屏幕。更改终端不是一个选项,因此我正在寻找变通方法(向下滚动$LINES行肯定不是完美的解决方案,但至少比丢失前一个屏幕更好)

11 个答案:

答案 0 :(得分:78)

您可以从tput获取行和列:

#!/bin/bash

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

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

答案 1 :(得分:18)

因为这个问题很受欢迎,所以我想添加一个更新的答案和一些额外的信息。

通常,在现代系统中,$COLUMNS$LINES变量是不是环境变量。 shell在每个命令之后动态设置这些值,我们通常无法从非交互式脚本访问它们。如果我们 export 它们,某些程序会尊重这些值,但这种行为不是标准化的或普遍支持的。

当我们使用以下命令启用checkwinsize选项时,Bash会将这些变量设置在进程(而非环境)的范围内:

shopt -s checkwinsize 

许多系统在默认或系统范围的启动文件( / etc / bashrc 或类似的)中为我们启用此选项,因此我们需要记住这些变量可能并不总是可用。在某些系统上,例如Cygwin,此选项为我们启用 ,因此Bash不设置$COLUMNS$LINES,除非我们执行上面的行或将其添加到我们的〜/ .bashrc

在编写非交互式脚本时,我们通常不希望默认依赖$LINES$COLUMNS(但我们可以检查这些以允许用户如果需要,手动覆盖终端尺寸。)

相反,sttytput实用程序提供 portable 意味着从脚本确定终端大小(下面描述的命令是currently undergoing standardization for POSIX)。< / p>

Puppe所接受的答案所示,我们可以使用tput以非常简单的方式收集终端尺寸:

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

或者,对size的{​​{1}}查询在一步中为我们提供终端行和列的数量(输出为行数,后跟两个空格,后跟列数): / p>

stty

size=$(stty size) # "40 80" for example 程序通常附带GNU Coreutils,因此我们经常可以在没有stty的系统上找到它。我有时更喜欢tput方法,因为我们调用一个较少的命令和子shell(在Cygwin上很昂贵),但它确实要求我们将输出解析为行和列,这可能不太可读:

stty

上述两种方法都适用于任何POSIX shell。特别是对于Bash,我们可以使用process substitution来简化前面的示例:

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

...比read lines columns < <(stty size) 示例运行得更快,但仍然比第一个tput实施慢,至少在我的机器上。在实践中,性能影响可能是微不足道的 - 选择最适合程序的方法(或基于目标系统上可用的命令)。

如果由于某种原因,我们仍希望在脚本中使用stty$LINES,我们可以配置Bash将这些变量导出到环境中:

$COLUMNS

Bash trap 'export LINES COLUMNS' DEBUG 陷阱在提示输入的每个命令之前执行,因此我们可以使用它来导出这些变量。通过使用每个命令重新导出它们,我们确保在终端大小更改时环境变量保持最新。将此行添加到 .bashrc 以及上面显示的DEBUG选项。它适用于个人脚本,但我不建议在任何将共享的脚本中使用这些变量。

答案 2 :(得分:6)

eval $( resize )

完成这项工作......(在基于xterm的终端上)

答案 3 :(得分:5)

kill -s WINCH $$

设置变量。

答案 4 :(得分:4)

为了完成,我要提一下,设置'checkwinsize'选项正是OP正在寻找的,但有一个问题。默认情况下,它在非交互式脚本中未设置,但您可以选择在任何脚本的开头添加以下行以启用它:

shopt -s checkwinsize

不幸的是,LINES和COLUMNS变量在设置选项时没有立即设置(至少我上次尝试时)。相反,您需要强制Bash等待子shell完成,此时它将设置这些变量。因此,针对此问题的完全Bash解决方案是使用以下行启动脚本:

shopt -s checkwinsize; (:;:)

然后,您可以将LINES和COLUMNS变量用于您的内容,每次调整终端大小时,它们都将重置为正确的值,而无需调用任何外部实用程序。

答案 5 :(得分:2)

你试过让你的shebang说:

#!/bin/bash -i

答案 6 :(得分:2)

运行help export可能有帮助吗?

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

答案 7 :(得分:1)

bash中的

$LINES$COLUMNS只是围绕TTY ioctls的shell-y包装器,它为您提供TTY的大小以及每次大小更改时终端发送的信号。

您可以使用其他语言编写程序,直接调用这些ioctl以获取TTY维度,然后使用该程序。

编辑:嗯,事实证明该程序已经存在,并被称为tput。投票Puppe's tput based answer

答案 8 :(得分:1)

#!/bin/bash -i

-i现在可以在 Ubuntu 11.10 上使用 bash 4.2.10(1)-release 工作。

$ 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.

数字会随着窗口调整大小而改变;陷阱显示脚本正在获得SIGWINCH。

答案 9 :(得分:0)

为什么不在exec命令上使用环境变量,如下所示:

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

答案 10 :(得分:-1)

我的经验是你应该通过&#39;来启动脚本。 script_to_run&#39;形式,而不是'scritp_to_run&#39;。一个简单的检查如下:

'(( ${#COLUMNS} )) || { echo "Try start like '. name'" ; return 1 ; }