LINES and COLUMNS environment variables lost in script

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, not environment variables and therefore are not exported to the child process (but they are automatically updated when I resize the xterm window, even when I log in via ssh from a remote place). Is there a way for my script to know the current size of the terminal?

EDIT: I need this as a solution to this problem : vi (as well as vim, less, and similar commands) will ruin the screen every time I use it. Changing the terminal is not an option, and so I'm looking for workarounds (scrolling down $LINES lines is certainly not an ideal solution, but at least better than losing the previous screen)

+45
bash shell terminal environment-variables
Nov 23 '09 at 0:01
source share
8 answers

You can get rows and columns from tput :

 #!/bin/bash lines=$(tput lines) columns=$(tput cols) echo "Lines: " $lines echo "Columns: " $columns 
+62
Nov 23 '09 at 12:36
source share
 kill -s WINCH $$ 

sets variables.

+6
Aug 29 '12 at 14:20
source share
 eval $( resize ) 

does the job ... (on an xterm based terminal)

+6
Sep 17 '13 at 10:36 on
source share

Have you tried to get your shebang to say:

 #!/bin/bash -i 
+3
Nov 23 '09 at 0:33
source share

Can help export work?

 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:~$ 
+2
Sep 09 '16 at 17:46
source share

$LINES and $COLUMNS in bash is just a wrapper around TTY ioctls, giving you the TTY size and signals sent by the terminal every time that size changes.

You can write the program in another language that calls these ioctls directly to get the TTY sizes, and then use this program.

EDIT: Well, it turns out that the program already exists and is called tput . Vote Puppe tput based on response .

+1
Nov 23 '09 at 14:14
source share
 #!/bin/bash -i 

-i now works with bash 4.2.10 (1) -release on 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. 

The numbers change with the size of the window; the trap indicates that the script is receiving SIGWINCH.

0
Dec 09 2018-11-11T00:
source share

Since this question is popular, I want to add a newer answer with more information.

The $COLUMNS and $LINES variables are not environment variables. These values ​​are dynamically set by the shell after each command, and we usually cannot access it from non-interactive scripts.

Bash sets these variables when we checkwinsize parameter using:

 shopt -s checkwinsize 

On many systems, this option is used for the default file or for the entire system file ( bashrc ), so we need to remember that these variables may not be available. On some systems, such as Cygwin, this option is not enabled for us, so Bash will not install $COLUMNS and $LINES unless we run the line above or add it to our .bashrc .




When writing non-interactive scripts, we cannot use $LINES and $COLUMNS by default. Instead, the stty and tput utilities provide portable tools for determining the size of a terminal from a script (the commands that are currently being standardized for POSIX are described below).

As shown in the current accepted answer, we can use tput to compile the size of the terminal quite simply:

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

Alternatively, the size request for stty gives us the number of rows and columns of the terminal in one step (displayed as the number of columns followed by two spaces followed by the number of rows):

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

I sometimes prefer the stty approach because we invoke another command and subshell (expensive on Cygwin), but it requires us to analyze the output in rows and columns, which may be less readable:

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

Both approaches described above work in any POSIX shell. For Bash in particular, we can use process overrides to simplify the previous example:

 read columns lines < <(stty size) 

... which works 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 is best for the program (or based on which command is available on the target system).




If for some reason we want to use $LINES and $COLUMNS in our scripts, we can configure Bash to export these variables to the environment:

 trap 'export LINES COLUMNS' DEBUG 

The DEBUG trap is executed before each command entered at the prompt, so we can use it to export these variables. By re-exporting them after each command, we guarantee that the environment variables will be updated if the terminal size changes. Add this line to .bashrc . It works great for personal scripts, but I do not recommend using these variables in any script that will be shared.

0
Dec 29 '17 at 1:29 on
source share



All Articles