When I uss
less file1 file2 I get both files shown in the "less buffer viewer", but
less file1 file2 | cat prints the content of both files appended to stdout. How does less know if it should show the "less buffer viewer" or produce output to stdout for a next command? What mechanism is used for doing this?
When I uss
less prints text to stdout. stdout goes
- to a terminal (/dev/tty?) and opens the default buffer viewer
- through a pipe when piping it to another programm using | (
less text | cut -d: -f1)
- to a file when redirecting it with > (
less text > tmp)
There is a C function called "isatty" which checks if the output is going to a tty (less 4.81, main.c, line 112). If so, it uses the buffer viewer otherwise it behaves like
In bash you can use test (see
- -t FD file descriptor FD is opened on a terminal
- -p FILE exists and is a named pipe
[[ -t 1 ]] && \ echo 'STDOUT is attached to TTY' [[ -p /dev/stdout ]] && \ echo 'STDOUT is attached to a pipe' [[ ! -t 1 && ! -p /dev/stdout ]] && \ echo 'STDOUT is attached to a redirection'
less checks if its
stdout is a terminal, and behaves like
cat when it isn't (copies stdin to stdout until EOF).
This feature lets you write scripts or programs that always send their output (e.g.
--help output) through
less while still allowing easy redirection to a file. It would suck if
some_command --fullhelp > help.txt still waited for space-bar on stdin to page through the text, or something. Some commands (e.g.
man) check that their own output to decide whether to send their output through a pager or not. If you run
man ls > ls.txt, it never invokes your
less's cat-like behaviour is handy if you forget to edit it out of a one-liner when adding more stages to a pipeline, too.
less needs to figure out the terminal dimensions (screen size, to know how many lines to show at once). The
ioctl(2) it uses on
stdout would return ENOTTY on a non-terminal, so it can't avoid handling the non-terminal case anyway.
less actually uses
isatty(3) before checking the terminal dimensions, but
isatty works by trying a tty-only ioctl and checking for lack of error.
Even a simple pager like
more(1) (at least the util-linux version) has this feature, because it's probably the simplest sane behaviour to implement for that case.
Note that when you pipe something into
grep foo bar.txt | less), it does have to open
/dev/tty for keyboard input. (You can see it do this with
echo foo | strace less).