Date:        Tue, 12 May 2026 10:24:17 -0400
    From:        Chet Ramey <[email protected]>
    Message-ID:  <[email protected]>

  | > That is not what LINES and COLUMNS are intended to be
  | > (or ever were).   They're supposed to be a method for the user to
  | > override the default settings for length/width, not a method to find
  | > out what the default settings are.
  |
  | This breaks down in the face of SIGWINCH, especially when it is sent to
  | a child process while job control is active, and the shell doesn't
  | receive it.

Huh?   Sorry, that makes no sense at all.   Please re-read what I said, and
then explain how that response is relevant.

It seems as if you're trying to explain how checkwinsize works, and why,
which has nothing whatever to do with the primary problem.   There's nothing
at all wrong with having something like checkwinsize being run by the shell,
it just shouldn't be setting LINES or COLUMNS (it could set BASH_LINES and
BASH_COLUMNS if you wanted ... see below.)

  | Since bash uses COLUMNS (for select, if you disregard everything else),

As it should (assuming one admits select should even exist, but that
question isn't relevant here) and so should lots of other commands, eg
kill (for kill -l) should use it as well, for working out how wide the
output should be (how many columns of signal names fit on each line).
In bash it doesn't, but it should, the same should be true of many other
commands with similar behaviour -- but certainly not all, an obvious
example is cat, which simply writes characters (if given a text file)
from each line up to the line ending, regardless of how wide the output
device might happen to be.

That is, if COLUMNS is set, use it, unless a command line option has
set something different, in which case use that.   Otherwise find out
from the system (perhaps using tcgetwinsize() ) what the size is.
If that fails, (and a terminal is in use) perhaps look for the size
info corresponding to TERM (but if a terminal is in use, tcgetwinsize
will probably work).   If all else fails, pick some reasonable default.

  | it is an unnecessary burden for the user to have to manually reset
  | COLUMNS after a window size change.

Why would the user ever want to do that?   The user is only supposed
to set those when a particular size is required, if that is the case,
what the actual window size might be is irrelevant, and so are any
changes made to it.

  | That's the whole rationale for `checkwinsize' to exist.

And that's fine, it just shouldn't set LINES and COLUMNS.
 
  | > The standard is quite clear:  [...]

  | This assumes that something will change LINES and COLUMNS in response to
  | changes to `the terminal characteristics'.

It assumes nothing of the kind.

  | The standard assumes those are immutable

Nor does it assume that.

  | (especially with its reference to $TERM), but reality is different.

Yes, getting terminal sizes from termcap (or terminfo) or any other
static database is almost a last resort type of issue, perhaps just
one step up from "everything has 80 columns".

  | Except that we live in 2026, not 1992. That language has survived
  | essentially unchanged since the first issue of 1003.2,

Which if anything is exactly the point.   There's never been any
question what LINES and COLUMNS are intended to be for, and it has
*never* been to provide information about the size of anything.
They are directive variables, and always have been, not informative.

Back to the standard again:

        Users should not need to set this variable in the environment
        unless there is a specific reason to override the implementation's
        default behavior, such as to display data in an area arbitrarily
        smaller than the terminal or window.

They are to be set when one wants to override the real size, and for
some reason, use something different.   With the NetBSD shell I sometimes
use

        COLUMNS=1 kill -l

to get the output in one vertical list, rather than as multiple columns
(1 seems a bit small, & 2 3 or 4 would work the same way - as each signal
name is written, unbroken, on one line, then when that line has reached far
enough that the next signal name would go beyond COLUMNS (including if
the current line already exceeded that), a newline is written first).

  | but expectations have changed.

What has changed is that some shells (probably starting from ksh)
decided to change the meaning of LINES & COLUMNS and use them to
provide information, which was never their purpose.   That's unfortunate.

Other shells (yash, bosh, dash (and other ash derived shells) don't).

  | Sure, ok, then how about `select'?

Select should use COLUMNS (does it also use LINES?) to set the width
for its menu (I am guessing that is its purpose, I've never used select,
and have no desire to ever do so - that is truly a primitive interface).
If COLUMNS is not set, it should use the current terminal width.

Your error is assuming that those two are the same thing, which is
exactly what they are not supposed to be.   The whole point of those
variables is for when the user wants to override the actual terminal
width/depth and use something different (without changing the size of
the terminal).  How well that works depends upon the application, and
whether the user is asking for more, or for less, than actually exists,
but that's all up to the user.

  | Or other applications that use LINES and COLUMNS as they appear
  | in the environment and expect them to be accurate?

They should use them if set and relevant to the application.   "accurate"
is meaningless in this regard.  If you mean "assume them to be the same
as the actual terminal size" then no, they should be assumed to be
different from the actual terminal size, if an application cannot operate
correctly without knowing the actual terminal size, it should ignore those
variables.   But it doesn't need to, if the user set those things to some
particular value, then the application should do what the user requested.

  | Why should the shell leave this burden up to the user?

What burden?   If some application is only able (or willing) to use
LINES/COLUMNS to get size information, and it needs that info, it is broken.

bash certainly needs to know the terminal size (for readline editing, more
than for select) and certainly works when no-one has provided LINES or
COLUMNS for it in the environment, or elsewhere, why should other applications
be different?

In practice, I almost never have LINES or COLUMNS set, except inside bash,
and they are not exported there (they're certainly not in any environment
when bash is started) - and I've never had an issue with any application
needing to be told somehow what the terminal size is (many like to be told
how big I would like them to be, when they create a window, but except for
terminal emulators, that info is usually conveyed in pixels, not char sized
units).

What would your impression be if some new application decided that it
needed to make the user's home (postal) address available - it already
has an ADDRESS variable it uses for destinations, so it decides that
the user's home address should be HOME, so it defines that, and
sets it like:

        HOME='1234 main street, capital city, funkyland'

and exports it.   All seems reasonable to the application designer,
assuming they don't know that HOME already has a defined meaning, and it
is not that.  The way ksh (and bash, etc) are using LINES and COLUMNS
is exactly this.

Note I am not saying that bash (or any other shell) cannot make the
current size info available to applications if it desires, bash has a
zillion variables which it sets to convey information to application
(or the user perhaps), and it could easily create one or two more for
this purpose - it just should not choose (have chosen now) names that
were already defined for a different purpose, no matter how similar the
purpose might seem to be.

But even if it doesn't (dash, yash, the NetBSD sh, don't) and a user
needs that info, then as [email protected] just said:

        >> POSIX.1-2024 adds "size" request to stty(1):

So a user (or script) can just do

        tsize() { set -- $(stty size); rows=$1 cols=$2; }
        trap tsize WINCH
        tsize

(the last line just to "prime the pump" it can be repeated any
other time it might be needed).   That works fine - I was planning
to use that as an example, just just referring to NetBSD's stty command
(probably any BSD stty command) when I saw Steffen's message (if I ever
saw POSIX had added that, I had since forgotten, so thanks.)

Any application which cares about terminal sizes already needs to deal
with this issue, as the terminal size can change while they are running,
and the LINES and COLUMNS variables they may have been provided with in
the environment certainly do not magically alter when that happens.

It is in general unfortunate that a standard method to get this info has taken
so long to eventuate, but that does not excuse having usurped the perfectly
simple (and well defined) definitions of LINES and COLUMNS to use them
"just because there is nothing else defined".    Unfortunately, now we
have a mess, with some shells setting those vars, totally inappropriately,
and others not (following the standard).

And lastly, wrt your slightly earlier message:

[email protected] said:
  | Since many (most) terminal emulators set LINES and COLUMNS in the
  | environment they provide to the shell they invoke,

There might certainly be some that do that, but nothing I have here
acts that way.   xterm certainly does not.  Nor does rxvt.

kre


Reply via email to