bash LINES 和 COLUMNS 环境变量在脚本中丢失
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1780483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
LINES and COLUMNS environmental variables lost in a script
提问by Davide
Consider the following:
考虑以下:
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:~$
The variables $LINES
and $COLUMNS
are shell variables, notenvironmental variables, and thus are not exported to the child process (but they are automatically updated when I resize the xterm window, even when logged in via ssh from a remote location). Is there a way in which I can let my script know the current terminal size?
变量$LINES
和$COLUMNS
是 shell 变量,而不是环境变量,因此不会导出到子进程(但是当我调整 xterm 窗口的大小时,即使从远程位置通过 ssh 登录,它们也会自动更新)。有没有办法让我的脚本知道当前的终端大小?
EDIT:
I need this as a workaround do this problem: vi (as well as vim, less, and similar commands) messes up the screen every time I use it. Changing the terminal is not an option, and thus I'm looking for workarounds (scrolling down $LINES
lines surely is not the perfect solution, but at least is better than losing the previous screen)
编辑:我需要这个作为解决这个问题的解决方法:vi(以及 vim、less 和类似命令)每次使用时都会弄乱屏幕。更改终端不是一种选择,因此我正在寻找解决方法(向下滚动$LINES
行肯定不是完美的解决方案,但至少比丢失前一个屏幕要好)
回答by Puppe
You could get the lines and columns from tput
:
您可以从tput
以下位置获取行和列:
#!/bin/bash
lines=$(tput lines)
columns=$(tput cols)
echo "Lines: " $lines
echo "Columns: " $columns
回答by Cy Rossignol
Because this question is popular, I want to add a newer answer with a bit of additional information.
因为这个问题很受欢迎,所以我想添加一个带有一些额外信息的新答案。
Often, on modern systems, the $COLUMNS
and $LINES
variables are notenvironment variables. The shell sets these values dynamically after each command and we usually cannot access them from non-interactive scripts. Some programs respect these values if we exportthem, but this behavior isn't standardized or universally supported.
通常,在现代系统上,$COLUMNS
和$LINES
变量不是环境变量。shell 在每个命令之后动态设置这些值,我们通常无法从非交互式脚本访问它们。如果我们导出这些值,一些程序会尊重这些值,但这种行为并未标准化或普遍支持。
Bash sets these variables in the scope of the process(not the environment) when we enable the checkwinsize
option using:
当我们使用以下选项启用选项时,Bash 在进程范围内(而不是环境)设置这些变量checkwinsize
:
shopt -s checkwinsize
Many systems enable this option for us in a default or system-wide startup file (/etc/bashrcor similar), so we need to remember that these variables may not always be available. On some systems, such as Cygwin, this option is notenabled for us, so Bash doesn't set $COLUMNS
and $LINES
unless we execute the line above or add it to our ~/.bashrc.
许多系统在默认或系统范围的启动文件(/etc/bashrc或类似文件)中为我们启用此选项,因此我们需要记住这些变量可能并不总是可用。在某些系统上,例如 Cygwin,我们未启用此选项,因此不会设置 Bash $COLUMNS
,$LINES
除非我们执行上面的行或将其添加到我们的~/.bashrc 中。
Portable Approaches
便携式方法
When writing non-interactive scripts, we usually don't want to rely on $LINES
and $COLUMNS
by default (but we cancheck these to allow a user to override the terminal size manually if desired).
在编写非交互式脚本时,我们通常不想依赖$LINES
和$COLUMNS
默认(但我们可以检查这些以允许用户在需要时手动覆盖终端大小)。
Instead, the stty
and tput
utilities provide portablemeans to determine the terminal size from a script (the commands described below are currently undergoing standardization for POSIX).
相反,stty
和tput
实用程序提供了从脚本确定终端大小的便携方法(下面描述的命令目前正在为 POSIX 进行标准化)。
As shown in the accepted answer by Puppe, we can use tput
to gather the terminal size in a pretty straightforward manner:
如Puppe接受的答案所示,我们可以使用tput
一种非常简单的方式来收集终端大小:
lines=$(tput lines)
columns=$(tput cols)
Alternatively, the size
query for stty
gives us the number of terminal rows and columns in one step (output as the number of lines followed by two spaces followed by the number of columns):
或者,size
查询 forstty
为我们提供一步中终端的行数和列数(输出为行数后跟两个空格后跟列数):
size=$(stty size) # "40 80" for example
The stty
program usually ships with GNU Coreutils, so we can often find it on systems without tput
. I sometimes prefer the stty
approach because we invoke one fewer command and subshell (expensive on Cygwin), but it does require that we parse the output into rows and columns, which may be less readable:
该stty
程序通常随GNU Coreutils 一起提供,因此我们经常可以在没有tput
. 我有时更喜欢这种stty
方法,因为我们调用的命令和子 shell 少了一个(在 Cygwin 上很昂贵),但它确实需要我们将输出解析为行和列,这可能不太可读:
lines=${size% *}
columns=${size#* }
Both of the approaches described above work in any POSIX shell.
上述两种方法都适用于任何 POSIX shell。
Non-portable Approaches
非便携式方法
If we don't care about portability, Bash supports process substitutionto simplify the previous example:
如果我们不关心可移植性,Bash 支持进程替换来简化前面的例子:
read lines columns < <(stty size)
...which runs faster than the tput
example, but still slower than the first stty
implementation, at least on my machine. In practice, the performance impact is probably negligible—choose the approach that works best for the program (or based on which command is available on the target system).
...运行速度比tput
示例快,但仍然比第一个stty
实现慢,至少在我的机器上。在实践中,性能影响可能可以忽略不计——选择最适合程序的方法(或基于目标系统上可用的命令)。
For Bash versions 4.3 and later, we can exploit the checkwinsize
option to avoid a dependency on an another program. When we enable this option in a script, Bash will set $LINES
and $COLUMNS
like it does for an interactive prompt aftera child process exits:
对于 Bash 4.3 及更高版本,我们可以利用该checkwinsize
选项来避免对另一个程序的依赖。当我们在脚本中启用此选项时,Bash 将在子进程退出后设置$LINES
并$COLUMNS
像交互式提示一样:
#!/bin/bash
shopt -s checkwinsize
cat /dev/null # Refresh LINES and COLUMNS
...like when a subshell exits:
...就像当子shell退出时:
shopt -s checkwinsize
(: Refresh LINES and COLUMNS)
Bash fetches the terminal size after everyexternal command invocation if we enable this option, so we may want to turn it back off after initializing the variables:
如果启用此选项,Bash 会在每次外部命令调用后获取终端大小,因此我们可能希望在初始化变量后将其关闭:
shopt -u checkwinsize
If, for some reason, we still want to use $LINES
and $COLUMNS
from the environment in our scripts, we can configure Bash to export these variables to the environment:
如果出于某种原因,我们仍然想在脚本中使用$LINES
和$COLUMNS
来自环境,我们可以配置 Bash 将这些变量导出到环境中:
trap 'export LINES COLUMNS' DEBUG
The Bash DEBUG
trap executes before each command entered at the prompt, so we can use it to export these variables. By re-exporting them with each command, we ensure that the environment variables remain up-to-date if the terminal size changes. Add this line to .bashrcalong with the checkwinsize
option shown above. It works fine for personal scripts, but I don't recommend using these variables in any script that will be shared.
BashDEBUG
陷阱在提示符下输入的每个命令之前执行,因此我们可以使用它来导出这些变量。通过使用每个命令重新导出它们,我们确保在终端大小发生变化时环境变量保持最新。将此行与上面显示的选项一起添加到.bashrccheckwinsize
中。它适用于个人脚本,但我不建议在任何将共享的脚本中使用这些变量。
回答by Anthony
eval $( resize )
does that job...(on xterm-based terminal)
做那个工作...(在基于 xterm 的终端上)
回答by elo
kill -s WINCH $$
does set the variables.
确实设置了变量。
回答by Marc Coiffier
For the sake of completion, let me mention that setting the 'checkwinsize' option is exactly what the OP is looking for, but there is a catch. It is by default unset in non-interactive scripts, but you can elect to add the following line at the beginning of any script to enable it :
为了完成起见,让我提一下,设置 'checkwinsize' 选项正是 OP 正在寻找的,但有一个问题。默认情况下,它在非交互式脚本中是未设置的,但您可以选择在任何脚本的开头添加以下行以启用它:
shopt -s checkwinsize
Unfortunately, the LINES and COLUMNS variables are not set immediately upon setting the option (at least the last time I tried). Instead, you need to force Bash to wait for a subshell to complete, at which point it will set those variables. The full Bash-only solution to this problem is thus to start your script with the following line :
不幸的是,LINES 和 COLUMNS 变量在设置选项后不会立即设置(至少在我最后一次尝试时)。相反,您需要强制 Bash 等待子 shell 完成,此时它将设置这些变量。因此,此问题的完整 Bash 解决方案是使用以下行启动您的脚本:
shopt -s checkwinsize; (:;:)
You can then use the LINES and COLUMNS variables to your heart's content, and they will be reset to the correct values each time the terminal is resized, without needing to call any external utilities.
然后,您可以根据自己的需要使用 LINES 和 COLUMNS 变量,每次调整终端大小时,它们将被重置为正确的值,而无需调用任何外部实用程序。
回答by Paused until further notice.
Have you tried making your shebang say:
你有没有试过让你的shebang说:
#!/bin/bash -i
回答by SwordFish
Running help export
might help?
跑步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:~$
回答by ndim
$LINES
and $COLUMNS
in bash is just a shell-y wrapper around the TTY ioctls giving you the size of the TTY and the signals sent by the terminal every time that size changes.
$LINES
而$COLUMNS
在bash就要到了TTY的ioctl给你TTY大小的外壳-Y包装和终端每次发送的大小变化的信号。
You could write a program in some other language which calls those ioctls directly to get to the TTY dimensions, and then use that program.
您可以使用其他语言编写程序,直接调用这些 ioctl 以获取 TTY 维度,然后使用该程序。
EDIT: Well, turns out that program already exists, and is called tput
. Vote up Puppe's tput
based answer.
编辑:嗯,原来该程序已经存在,并被称为tput
. 投票支持Puppe 的tput
答案。
回答by Seganku
#!/bin/bash -i
-i
works now with bash 4.2.10(1)-releaseon Ubuntu 11.10.
-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.
The numbers do change with a window resize; a trap reveals the script is getting a SIGWINCH.
数字会随着窗口大小的调整而改变;一个陷阱显示脚本正在收到 SIGWINCH。
回答by Classsic
Why not use enviroment variables on exec command like this:
为什么不在这样的 exec 命令上使用环境变量:
docker exec -ti -e LINES=$LINES -e COLUMNS=$COLUMNS container /bin/bash