The less -S recommendation is a complete nonstarter, because it causes less to send symbolic representations of control characters to the terminal rather than passing them raw.
Without the -S option, less can perfectly well unwrap lines, and send control characters to the terminal for syntax coloring and whatnot. The program demonstrates this ability whenever you use the arrow keys to scroll horizontally. As soon as you scroll away from column 1, the lines show without wrapping, yet with all the terminal effects intact.
All that users want is the same unwrapping to work in column 1 also.
Here is a hack script to clumsily bring it about:
#!/bin/sh
halfscreen=$((COLUMNS / 2))
spaces=$(printf "%*s" $halfscreen "")
sed -e "s/^/$spaces/' | less -# $halfscreen
We save this script under some name like lesshack.sh and make sure it is executable via chmod +x lesshack.sh. Then we use the script as the pager.
It relies on the COLUMNS variable, so we have to make sure this is exported into the environment via export COLUMNS.
How does this work? The script reads from standard input, and prepends half a screen width's worth of spaces to the beginning of each line.
When less comes up, we hit the right arrow key to scroll half a screen width to the right. That precisely skips the spaces we have added. So now we are looking at an unwrapped view of our data, without the -r option being disabled.
On Linux, we can inject the initial right arrow command into less via the TTY, using the TIOCSTI system call.
We switch the script to Bash, and add the ttyinject command, which we have to develop ourselves:
#!/bin/bash
halfscreen=$((COLUMNS / 2))
spaces=$(printf "%*s" $halfscreen "")
ttyinject $'\eOC' < /dev/tty
sed -e "s/^/$spaces/" | less -# $halfscreen
The ttyinject utility inserts the specified characters into the TTY, as if they were input. It's a giant security hole that may have been disabled by default in Linux 6, but it's working for me on a system with a 5 kernel.
We are using $'\eOC. $'...' is Bash-specific syntax for a string literal in which C-like character escape sequences are interpreted. The \e escape is a GNU extension denoting ASCII ESC. ESC O C is the ANSI/VT100 right arrow sequence.
Here is the source code for ttyinject:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
int main(int argc, char *argv) {
if (argv[0] && argv[1]) {
char inj = argv[1];
while (*inj) {
if (ioctl(STDIN_FILENO, TIOCSTI, inj++) == -1) {
perror("ioctl(TIOCSTI)");
return EXIT_FAILURE;
}
}
}
return 0;
}
One less refinement. With the above script, I see the injected characters being echoed to the terminal. They can be seen when less terminates and restores the screen. This is untidy. What we can do is run ttyinject in the background and with a small delay so that it takes effect after less has already started and switched the TTY to raw mode, disabling echo:
#!/bin/bash
halfscreen=$((COLUMNS / 2))
spaces=$(printf "%*s" $halfscreen "")
(sleep 0.1 ; ttyinject $'\eOC' < /dev/tty ) &
sed -e "s/^/$spaces/" | less -# $halfscreen