因为这个问题很受欢迎,所以我想添加一个更新的答案,并提供一些额外的信息。
通常,在现代系统中,$COLUMNS 和 $LINES 变量不是环境变量。 shell 在每个命令之后动态设置这些值,我们通常无法从非交互式脚本中访问它们。如果我们导出这些值,某些程序会尊重这些值,但这种行为并未标准化或普遍支持。
当我们启用checkwinsize 选项时,Bash 在进程(而不是环境)范围内设置这些变量:
shopt -s checkwinsize
许多系统在默认或系统范围的启动文件(/etc/bashrc 或类似文件)中为我们启用了此选项,因此我们需要记住这些变量可能并不总是可用。在某些系统上,例如 Cygwin,此选项没有为我们启用,因此 Bash 不会设置 $COLUMNS 和 $LINES,除非我们执行上面的行或将其添加到我们的 ~/.bashrc.
便携式方法
在编写非交互式脚本时,我们通常不希望默认依赖 $LINES 和 $COLUMNS(但我们可以检查这些以允许用户覆盖终端大小如果需要,可以手动)。
相反,stty 和 tput 实用程序提供了可移植 方法来通过脚本确定终端大小(下面描述的命令是 currently undergoing standardization for POSIX)。
如Puppe 接受的答案所示,我们可以使用tput 以非常简单的方式收集终端大小:
lines=$(tput lines)
columns=$(tput cols)
或者,size 查询 stty 一步即可为我们提供终端行数和列数(输出为行数,后跟两个空格,后跟列数):
size=$(stty size) # "40 80" for example
stty 程序通常附带GNU Coreutils,因此我们经常可以在没有tput 的系统上找到它。我有时更喜欢stty 方法,因为我们调用的命令和子shell(在Cygwin 上很昂贵),但它确实需要我们将输出解析为行和列,这可能不太可读:
lines=${size% *}
columns=${size#* }
上述两种方法都适用于任何 POSIX shell。
非便携式方法
如果我们不关心可移植性,Bash 支持process substitution 以简化前面的示例:
read lines columns < <(stty size)
...运行速度比tput 示例快,但仍比第一个stty 实现慢,至少在我的机器上是这样。在实践中,性能影响可能可以忽略不计——选择最适合程序的方法(或基于目标系统上可用的命令)。
对于 Bash versions 4.3 and later,我们可以利用 checkwinsize 选项来避免对另一个程序的依赖。当我们在脚本中启用此选项时,Bash 将设置 $LINES 和 $COLUMNS,就像它对交互式提示所做的那样子进程退出:
#!/bin/bash
shopt -s checkwinsize
cat /dev/null # Refresh LINES and COLUMNS
...就像子shell退出时一样:
shopt -s checkwinsize
(: Refresh LINES and COLUMNS)
如果我们启用此选项,每次外部命令调用后,Bash 都会获取终端大小,因此我们可能希望在初始化变量后将其关闭:
shopt -u checkwinsize
如果出于某种原因,我们仍想在脚本中使用环境中的 $LINES 和 $COLUMNS,我们可以配置 Bash 以将这些变量导出到环境中:
trap 'export LINES COLUMNS' DEBUG
Bash DEBUG 陷阱在提示符处输入每个命令之前执行,因此我们可以使用它来导出这些变量。通过使用每个命令重新导出它们,我们确保在终端大小发生变化时环境变量保持最新。将此行与上面显示的 checkwinsize 选项一起添加到 .bashrc 中。它适用于个人脚本,但我不建议在任何要共享的脚本中使用这些变量。