View Issue Details

IDProjectCategoryView StatusLast Update
00019741003.1(2024)/Issue8Shell and Utilitiespublic2026-03-14 01:15
Reportermkoskar Assigned To 
PrioritynormalSeverityObjectionTypeError
Status NewResolutionOpen 
NameMiroslav Koškár
Organization
User Reference
Section3 Utilities / tabs
Page Number3415
Line Number116444-116446
Interp Status
Final Accepted Text
Summary0001974: tabs: wrong description of semantics of arbitrary tab stops
DescriptionTo get tab stops with a standard interval of 8:
$ tabs -8

Analogous to that when arbitrary tab stops are used:
$ tabs 1,9,17,25

Tab stop value:

* is > 0
* represents a column (left-most being 1) where cursor moves and output occurs after preceding \t character
* as a special case, the 1st tab stop value is always 1 (whether explicitly specified or not) to demonstrate that without preceding \t character output occurs in the left-most column

The above is true for most common implementation of tabs from ncurses.

I believe that indicated sentence:

> The phrase "tab-stop position N" shall be taken to mean that, from the start
of a line of output, tabbing to position N shall cause the next character output
to be in the (N+1)th column position on that line.

is wrong with regards to what actual semantics of operand(s) is.

For additional context, this came up in following:

* https://github.com/gwsw/less/issues/737

I've tried to summarize in following comment:

* https://github.com/gwsw/less/issues/737#issuecomment-4033517061

Further of note are comments by @avih who were instrumental in tracking down
historical sources of tabs and its documentation.
Desired ActionRemove following sentence from the DESCRIPTION section:

> The phrase "tab-stop position N" shall be taken to mean that, from the start
of a line of output, tabbing to position N shall cause the next character output
to be in the (N+1)th column position on that line.

In OPERANDS section add following lines (demarcated with +++):

n[[sep[+]n]...] A single command line argument that consists of one or more tab-stop values (n)
                separated by a separator character (sep) which is either a <comma> or a <blank>
                character. The application shall ensure that the tab-stop values are positive decimal
                integers in strictly ascending order.

+++
                A tab-stop value shall be taken to mean a column (left-most
                being 1) where cursor moves and output occurs after preceding \t
                character. The 1st tab-stop value is always 1 (whether
                explicitly specified or not) to demonstrate that without
                preceding \t character output occurs in the left-most column.
+++

                If any tab-stop value (except the first one) is
                preceded by a <plus-sign>, it is taken as an increment to be added to the previous
                value. For example, the tab lists 1,10,20,30 and "1 10 +10 +10" are considered
                to be identical.
TagsNo tags attached.

Activities

mkoskar

2026-03-11 15:10

reporter   bugnote:0007395

Correction: I meant to reference following comment https://github.com/gwsw/less/issues/737#issuecomment-4030159904 instead.

wpollock

2026-03-11 17:02

reporter   bugnote:0007396

I think the terms left and right should be avoided,
since such directions do not account for right-to-left scripts (in tbe Unicode
sense of the term). "Beginning of line" and "end of line" might be better?

dickey

2026-03-11 19:39

reporter   bugnote:0007397

Column-1 is the first available position for a tab stop on a line.
An (ECMA-48 compatible) terminal can be set up so that the
first tab stop on a line is not on the first column.
The tabs program is documented to take this into account.

Given that (and spelling), the sentence

                "The 1st tab-stop value is always 1 (whether
                explicitly specified or not) to demonstrate that without
                preceding \t character output occurs in the left-most column."

needs some revision.

Rather than removing the obscurely-worded sentence with "tabbing to position N",
it should be revised to explain that tab-stops are 1-based, and that while the interval
between stops may be 8, the 1-based detail makes the stops one column past the
simple multiple of the tab interval.

(making that both concise and clear doesn't look simple -- but the existing description is concise)

mkoskar

2026-03-11 21:56

reporter   bugnote:0007398

My main objection to the sentence

> The phrase "tab-stop position N" shall be taken to mean that, from the start
> of a line of output, tabbing to position N shall cause the next character output
> to be in the (N+1)th column position on that line.

is that it implies that doing e.g.,

$ N=9 ; tabs 1,$N ; printf '\tX\n'

causes the letter "X" to be printed in the column (N+1)=10, instead of 9 (which
is in fact what happens).

So in keeping changes as minimal as possible, an alternative fix is amending the
above sentence and replacing "(N+1)th column" with "Nth column".

Note that the reason why the variation of above sentence works for
expand/unexpand is that "-t tablist" option in those utilities takes 0-based tab
stops but here tab stops are 1-based as @dickey also pointed out.

dickey

2026-03-11 22:29

reporter   bugnote:0007399

Regarding "expand" versus 1-based or 0-based, it states in

    https://pubs.opengroup.org/onlinepubs/9799919799/utilities/expand.html

    Each tab stop N shall be an integer value greater than zero, and the list is in strictly ascending order.

which is 1-based.

dickey

2026-03-11 22:40

reporter   bugnote:0007400

Regarding the tabbing to position N, I noticed an analogous issue in ECMA-48 section 8.3.61
(HTJ - character tabulation with justification) which describes behavior before the tab stop.
The original authors of the document may have had something like that in mind,
distinguish the tab movement (all whitespace) from the position where the next character
would be printed.

Since (without being familiar with terminals at that level), readers can get confused,
the goal here seems to be to rephrase things in clearer language without changing
the underlying technical content.

mkoskar

2026-03-13 09:49

reporter   bugnote:0007403

> which is 1-based.
Ah right, granted, I should have said as-if-0-based, at least that's how I think
about it.

Alternatively one can look at it such that "tab stop N" is either where:
1) N refers to column on which the next character should be printed.
or
2) N refers to column after which the next character should printed.

With regards to difference of e.g., `tabs 1,9,17` and `tabs 9,17` I stand
corrected. I assumed 1 is always implied. Investigating its output e.g., via
`xxd` or `od` reveals that latter does not put a tab stop on 1.

dickey

2026-03-14 01:15

reporter   bugnote:0007406

ECMA-48

https://ecma-international.org/publications-and-standards/standards/ecma-48/

standard for terminal controls (including cursor movement and tab stops) numbers
columns starting at 1. The (presumably) AT&T people who documented tabs had
that in mind. The tab stops are the columns on which the first character is printed
after tabbing to that column. There's some possible confusion over what happens
with the column just before the tab stop (because it may appear that the the tab
"must" go there. But it doesn't happen that way. The terminal simply skips over
the intervening columns (without modifying them) to prepare to show a printable
character at the tab stop. (If something other than a printable character follows,
that's outside the scope of this document, and is "unspecified").

Issue History

Date Modified Username Field Change
2026-03-11 15:00 mkoskar New Issue
2026-03-11 15:10 mkoskar Note Added: 0007395
2026-03-11 17:02 wpollock Note Added: 0007396
2026-03-11 19:39 dickey Note Added: 0007397
2026-03-11 21:56 mkoskar Note Added: 0007398
2026-03-11 22:29 dickey Note Added: 0007399
2026-03-11 22:40 dickey Note Added: 0007400
2026-03-13 09:49 mkoskar Note Added: 0007403
2026-03-14 01:15 dickey Note Added: 0007406