I'm trying to get the number of columns or lines of my terminal but the variables COLUMNS / LINES are always empty.
COLUMNS and LINES are set by BASH in interactive mode; they are not available by default in a script. On most systems, you can try to query the terminal yourself:
unsup() { echo "Your system doesn't support retrieving $1 with tput. Giving up." >&2; exit 1; } COLUMNS=$(tput cols) || unsup cols LINES=$(tput lines) || unsup lines
Bash automatically updates the COLUMNS and LINES variables when an interactive shell is resized. If you're setting the variables in a script and you want them to be updated when the terminal is resized, i.e. upon receipt of a SIGWINCH, you can set a trap yourself:
trap 'COLUMNS=$(tput cols) LINES=$(tput lines)' WINCH
You can also set the shell as interactive in the script's shebang:
#!/bin/bash -i
echo $COLUMNS
This has some drawbacks, however:
Though not the best practice, it's not too uncommon for scripts to test for the -i option to determine whether a shell is interactive, and then abort or misbehave. There is no completely foolproof way to test for this, so some scripts may break as a result.
Running with -i sources .bashrc, and sets various options such as job-control which may have unintended side-effects.
Though you can technically set -i in the middle of a script, it has no effect on the setting of COLUMNS and LINES. -i must be set when Bash is first invoked.
Normally Bash updates COLUMNS and LINES when your terminal sends a SIGWINCH signal, indicating a change of size. Some terminals may not do this, so if your variables aren't being updated even when running an interactive shell, try using the shopt -s checkwinsize. This will make Bash query the terminal after every command, so only use it if it's really necessary.
tput, of course, requires a terminal. According to POSIX, if stdout is not a tty, the results are unspecified, and stdin is unused, though some implementations may try using it anyway. On OpenBSD and Gentoo, and Debian Linux (and apparently at least some other Linuxes), at least one of stdout or stderr must be a tty, or else tput just returns some default values:
linux$ tput -S <<<$'cols\nlines' 2>&1 | cat 80 24 openbsd$ tput cols lines 2>&1 | cat 80 24