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

Dav*_*ide 62 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:~$ 
Run Code Online (Sandbox Code Playgroud)

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

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

Pup*_*ppe 80

您可以从tput以下位置获取行和列:

#!/bin/bash

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

echo "Lines: " $lines
echo "Columns: " $columns
Run Code Online (Sandbox Code Playgroud)

  • 对于cygwin 1.7或更高版本,您需要安装ncurses包以获取tput. (5认同)
  • 这应该注意: if [ -n "${TERM}" ]; 然后行=$(tput行);别的... (2认同)
  • @Aleksander`stty`命令包含在Cygwin的coreutils中,如果我们不需要安装ncurses,我们可以使用它来代替`tput`.我在一个例子中添加了答案. (2认同)
  • 我的终端有 197 列,但 tput 总是给我 80 (2认同)

Cy *_*nol 23

因为这个问题很受欢迎,我想添加一个更新的答案,其中包含一些额外的信息.

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

当我们使用以下选项启用选项时,Bash将这些变量设置在流程范围内(而不是环境)checkwinsize:

shopt -s checkwinsize 
Run Code Online (Sandbox Code Playgroud)

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


当写非交互式脚本,我们通常不希望依赖于$LINES$COLUMNS默认情况下(但我们可以检查这些允许如果需要,用户可以手动覆盖终端大小).

相反,sttytput实用程序提供了从脚本中确定终端大小的可移植方法(下面描述的命令目前正在进行POSIX的标准化).

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

lines=$(tput lines)
columns=$(tput cols)
Run Code Online (Sandbox Code Playgroud)

或者,size查询为stty我们提供一步中的终端行和列的数量(输出为行数,后跟两个空格,后跟列数):

size=$(stty size)  # "40  80" for example 
Run Code Online (Sandbox Code Playgroud)

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

lines=${size% *}
columns=${size#* }
Run Code Online (Sandbox Code Playgroud)

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

read lines columns < <(stty size) 
Run Code Online (Sandbox Code Playgroud)

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


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

#!/bin/bash
shopt -s checkwinsize
cat /dev/null # Refresh LINES and COLUMNS
Run Code Online (Sandbox Code Playgroud)

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

  • 很棒的答案。终于明白了为什么系统的行为如此不同......登录只是为了对此进行投票 - 并提示一个小错误:您在匹配`size`输出时恢复了行和列,应该是 .eg `lines=${size#* } `. `size` 输出第一行然后输出列。 (2认同)

小智 6

eval $( resize )
Run Code Online (Sandbox Code Playgroud)

做那个工作......(在基于xterm的终端上)


小智 6

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

shopt -s checkwinsize
Run Code Online (Sandbox Code Playgroud)

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

shopt -s checkwinsize; (:;:)
Run Code Online (Sandbox Code Playgroud)

然后,您可以根据自己的喜好使用 LINES 和 COLUMNS 变量,每次调整终端大小时,它们都会重置为正确的值,而无需调用任何外部实用程序。


小智 5

kill -s WINCH $$
Run Code Online (Sandbox Code Playgroud)

设置变量.

  • 尽管有意思. (2认同)

小智 5

跑步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:~$ 
Run Code Online (Sandbox Code Playgroud)