It's the shell that sets the pipeline up. less
is not involved in that.
When you do ls | less
, the shell starts ls
and less
concurrently after having made the stdout of the process that will eventually execute ls
the writing end of a pipe and the stdin of the one that will execute less
the reading end of that same pipe.
ls
detects that its stdout is not a tty device, and alters its behaviour accordingly. There's nothing that less
can do about it.
What the shell could do is use a pseudo-terminal pair instead of a pipe to connect the two processes, but that would be a bad idea, as pseudo-terminals were not designed for that. For one, the tearing down of the connection would be problematic. less
would probably be confused if its stdin was a pseudo-terminal master.
Another approach would be to get a 3rd process that reads the output of ls
via a pseudo-terminal pair and feeds it to less
via a pipe like with @JdeBP's ptyrun
or ptybandage
, or expect
's unbuffer
or using zsh
's zpty
builtin:
zmodload zsh/zpty
ttypager() { (zpty c "stty raw -echo; ${(q)@}"; zpty -r c) | less -RFX; }
ttypager ls
ls
would run in a new session in a new terminal, so would not receive SIGINT when you press ^C, or SIGPIPE when you quit less
before it finishes writing. However, since the process holding the master side (a subshell here) would still in those cases, ls
would receive a SIGHUP and die nonetheless.
zpty
here runs the command as if using eval
, so aliases are going to be expanded. Actually, they would be expanded even if you called ttypager \ls
as ttypager
would still receive ls
as argument and perform the alias expansion later.
Also note that both stdout and stderr would go to that pseudo-terminal and eventually to the pipe.
That's still a bit of a dirty hack. Here, the simplest would be to tell ls
to behave as if it was connected to a terminal.
You could use a helper function like:
paged_ls() { ls -C --color=always "$@" | less -RFX; }
Where -C
forces the output in column (which some implementations including GNU ls
do by default when the output goes to a terminal) and --color=always
force the output in colour regardless of whether the output goes to a terminal or not.