代码之家  ›  专栏  ›  技术社区  ›  Davide

脚本中丢失的行和列环境变量

  •  56
  • Davide  · 技术社区  · 15 年前

    考虑以下事项:

    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 是外壳变量, 环境变量,因此不会导出到子进程(但当我调整xterm窗口的大小时,即使是从远程位置通过ssh登录时,它们也会自动更新)。有没有一种方法可以让我的脚本知道当前的终端大小?

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

    11 回复  |  直到 6 年前
        1
  •  74
  •   heemayl    8 年前

    你可以从 tput :

    #!/bin/bash
    
    lines=$(tput lines)
    columns=$(tput cols)
    
    echo "Lines: " $lines
    echo "Columns: " $columns
    
        2
  •  17
  •   Cy Rossignol Albert    6 年前

    因为这个问题很流行,所以我想添加一个更新的答案,并提供一些附加信息。

    通常,在现代系统中, $COLUMNS $LINES 变量是 环境变量。shell在每个命令之后动态地设置这些值,我们通常无法从非交互式脚本访问这些值。如果我们 出口 但这种行为并没有被标准化或普遍支持。

    bash将这些变量设置在 过程 (不是环境)当我们启用 checkwinsize 选项使用:

    shopt -s checkwinsize 
    

    许多系统在默认或系统范围的启动文件中为我们启用此选项( /ETC/BASHC 或者类似的),所以我们需要记住,这些变量可能并不总是可用的。在某些系统上,如Cygwin,此选项是 为我们启用,所以bash不设置 美元专栏 美元线 除非我们执行上面的行或将其添加到 BASHC .


    在编写非交互式脚本时,我们通常不想依赖 美元线 美元专栏 默认情况下(但我们 可以 选中这些选项,允许用户根据需要手动覆盖终端大小)。

    相反, stty tput 公用设施提供 便携式的 从脚本确定终端大小的方法(下面描述的命令是 currently undergoing standardization for POSIX )

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

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

    或者, size 查询 斯蒂 给出一个步骤中终端行和列的数量(输出为行数,后跟两个空格,后跟列数):

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

    这个 斯蒂 程序通常随附 GNU Coreutils ,因此我们通常可以在没有 TTPT . 我有时更喜欢 斯蒂 方法是因为我们调用的命令和子shell更少(在cygwin上开销很大),但它确实要求我们将输出解析为行和列,这可能会降低可读性:

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

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

    read lines columns < <(stty size) 
    

    …比 TTPT 例如,但仍然比第一个慢 斯蒂 实现,至少在我的机器上。在实践中,性能影响可能可以忽略不计,选择最适合程序的方法(或基于目标系统上可用的命令)。


    如果出于某种原因,我们仍然想使用 $行 美元专栏 在我们的脚本中,我们可以配置bash将这些变量导出到环境中:

    trap 'export LINES COLUMNS' DEBUG
    

    迎头痛击 DEBUG 陷阱在提示下输入的每个命令之前执行,因此我们可以使用它来导出这些变量。通过使用每个命令重新导出它们,我们可以确保在终端大小发生变化时环境变量保持最新。将此行添加到 BASHC 以及 校验尺寸 上面显示的选项。它对个人脚本很好,但我不建议在任何将要共享的脚本中使用这些变量。

        3
  •  6
  •   tanascius    11 年前
    eval $( resize )
    

    那是不是…(在基于xterm的终端上)

        4
  •  5
  •   ronalchn Damien    12 年前
    kill -s WINCH $$
    

    设置变量。

        5
  •  3
  •   Marc Coiffier    6 年前

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

    shopt -s checkwinsize
    

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

    shopt -s checkwinsize; (:;:)
    

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

        6
  •  2
  •   Dennis Williamson    15 年前

    你试过让你的shebang说:

    #!/bin/bash -i
    
        7
  •  2
  •   SwordFish    8 年前

    运行 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:~$ 
    
        8
  •  1
  •   Community Nick Bolton    7 年前

    $LINES $COLUMNS 在bash中,仅仅是一个围绕tty ioctl的shell-y包装器,它为您提供tty的大小以及每次该大小改变时终端发送的信号。

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

    编辑:嗯,原来那个程序已经存在,并且被调用 tput . 投票表决 Puppe's tput based answer .

        9
  •  1
  •   Benjamin W.    7 年前
    #!/bin/bash -i
    

    -i 现在工作 bash 4.2.10(1)-发布 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.
    

    数字会随着窗口大小的改变而改变;陷阱显示脚本正在获取信号绞盘。

        10
  •  0
  •   Classsic    6 年前

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

    docker exec -ti -e LINES=$LINES -e COLUMNS=$COLUMNS  container /bin/bash
    
        11
  •  -1
  •   apexik    6 年前

    我的经验是,你应该从开始的脚本。脚本“to”run“形式,而不是“scritp”to“run”。简单检查如下:

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