25

I'm encountering an issue where I am trying to get the size of a terminal by using scripts. Normally I would use the command tput cols inside the console, however I want to be able to accomplish this feature by strictly using scripts.

As of now I am able to detect the running console and get its file path. However I'm struggling to use this information to get the console's width. I've attempted using the command tput, but I'm fairly new to Linux/scripts so therefore don't really know what to do.

The reason for doing this is I want to be able to setup a cron entry that notifies the console of its width/columns every so often.

This is my code so far:

tty.sh

#!/bin/bash

#Get PID of terminal
#terminal.txt holds most recent PID of console in use
value=$(</home/test/Documents/terminal.txt)

#Get tty using the PID from terminal.txt
TERMINAL="$(ps h -p $value -o tty)"
echo $TERMINAL

#Use tty to get full filepath for terminal in use
TERMINALPATH=/dev/$TERMINAL
echo $TERMINALPATH

COLUMNS=$(/home/test/Documents/get_columns.sh)
echo $COLUMNS

get_columns.sh

#!/usr/bin/env bash
echo $(/usr/bin/tput cols)

The normal output of TERMINAL & TERMINALPATH are pts/terminalnumber and /dev/pts/terminalnumber, for example pts/0 & /dev/pts/0

3
  • 1
    unix.stackexchange.com/questions/16578/… might help you.
    – phk
    Commented Jul 29, 2016 at 11:54
  • @phk I don't think that helps. The issue there is how to tell the tty driver of actual values for columns/lines. Here it is to determine them from the tty driver. Commented Jul 29, 2016 at 13:17
  • I didn't think cron jobs had controlling terminals.
    – TMN
    Commented Jul 29, 2016 at 16:08

4 Answers 4

28

The tput command is an excellent tool, but unfortunately it can't retrieve the actual settings for an arbitrarily selected terminal.

The reason for this is that it reads stdout for the terminal characteristics, and this is also where it writes its answer. So the moment you try to capture the output of tput cols you have also removed the source of its information.

Fortunately, stty reads stdin rather than stdout for its determination of the terminal characteristics, so this is how you can retrieve the size information you need:

terminal=/dev/pts/1
columns=$(stty -a <"$terminal" | grep -Po '(?<=columns )\d+')
rows=$(stty -a <"$terminal" | grep -Po '(?<=rows )\d+')

By the way, it's unnecessarily cumbersome to write this as echo $(/usr/bin/tput cols).

For any construct echo $(some_command) you are running some_command and capturing its output, which you then pass to echo to output. In almost every situation you can imagine you might as well have just run some_command and let it deliver its output directly. It's more efficient and also easier to read.

8
  • Which implementation/version of tput/nurses? Mine (ncurses 6.0.20160625) does the TIOCGWINSZ on stderr if it can't do it on stdout. cols=$(tput cols) or cols=$(tput cols 2<> /dev/ttyx) works just fine. Commented Jul 29, 2016 at 13:44
  • @StéphaneChazelas I've got 5.9+20140913-1+b1 originally installed from Debian "sid". Just looking for a newer version now. Commented Jul 29, 2016 at 13:49
  • 1
    Works as well with ncurses 5.7.20100313 here. Are you positive cols=$(tput cols 2<> /dev/tty1) doesn't work for you? Commented Jul 29, 2016 at 14:03
  • 3
    I'd use stty size <"$terminal" | read rows columns instead of trying to parse stty -a
    – Random832
    Commented Jul 30, 2016 at 7:17
  • 1
    @Random832 only this read r c < <(stty size) worked here, but thx :) Commented Jan 4, 2018 at 23:23
19

tput cols and tput lines query the size of the terminal (from the terminal device driver, not the terminal itself) from the terminal device on its stdout, and if stdout is not a terminal device like in the case of cols=$(tput cols) where it's then a pipe, from stderr.

So, to retrieve the values from an arbitrary terminal device, you need to open that device on the stderr of tput:

{ cols=$(tput cols) rows=$(tput lines); } 2< "$TERMINALPATH"

(here open in read-only mode so tput doesn't output its error messages there).

Alternatively, you may be able to use stty size. stty queries the terminal on stdin:

read rows cols < <(stty size < "$TERMINALPATH")

None of those are standard so may (and in practice will) not work on all systems. It should be fairly portable to GNU/Linux systems though.

The addition of stty size or other method to query terminal size was requested to POSIX but the discussion doesn't seem to be going anywhere.

0
16

This script:

#!/bin/bash

echo "The number of columns are $COLUMNS"
echo "The number of lines are $LINES"

Worked here with absolutely nothing more.....

Why you are setting a environment variable with data?

COLUMNS=$(/home/test/Documents/get_columns.sh)

Are you try to get the columns and lines from other script or tty? Is that it? Still strange for me because you're setting the columns environment variable for the local script....

6
  • This doesn't help retrieve the values within the OP's cron job for a particular terminal. Commented Jul 29, 2016 at 13:11
  • 1
    Ahn? What? Now i am more confused, how can cronjobs scripts can have width????? They actually not run in a terminal. Commented Jul 29, 2016 at 16:25
  • 1
    I know. The cron job queries a particular terminal for its characteristics. (I'm not entirely sure why it needs to do this, but that's what the OP wants.) Commented Jul 29, 2016 at 16:27
  • @LucianoAndressMartini $COLUMNS and $LINES are bash variables, it does not work (for example) in dash and posh
    – ingroxd
    Commented Sep 15, 2018 at 17:25
  • Tks. I really know, but my script is hashbang with /bin/bash i think it is supposed for you to know that you should use it. If you are using some unix without bash, maybe my answer not for you. Commented Sep 16, 2018 at 12:39
5

My answer is different than that of Roaima's, since it is dynamic. His/Hers answer gives you the size of the terminal at creation. If you are for example using a tiling window manager, like i3 or bspwm, you would rather want to have the current width of the terminal. Thus I use ssty from the coreutils package:

#!/bin/bash
stty size | awk '{print $2}'

Luciano's solution works flawless in xterm and xfce4-terminal. I dont know if all terminals set the $COLUMNS variable.

1
  • This is no more dynamic then my answer. Both give you the terminal size at the point you run the commands. Commented Dec 1, 2018 at 7:58

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.