3

I'm pretty sure seeing this customization of the less command on some colleague system long ago, in order to imitate 'more'. What I want:

  • If the file is short (less that one screen long), it should behave like cat: it shows the content of the file and exits.

  • If the file is longer than one screen, it should behave as usual, waiting for user input and clearing its screen on exit and leaving the previous commands on the screen.

I've tried experimenting with less -FX, but it leaves tons of stuff on the screen for large files.

1
  • 2
    Have you tried with just -F? -X seems to do skip terminal initialization, so maybe that's why it leaves the screen garbled. Sep 6, 2018 at 12:29

3 Answers 3

4

If I understand you correctly, you would like to keep the alternate screen switching behaviour for large files, and turn the -X switch on only for small files that fit on single screen and don't need scrolling.

That is now the default behavior in version 530 of less; quoting from the NEWS file from its source code:

Major changes between less versions 487 and 530

  • Don't output terminal init sequence if using -F and file fits on one screen.

Unfortunately, as of 2019, some distros like Debian 10 still use older versions of less, so if you don't want to build it from sources, the only solution is to use a wrapper.

Here is an example of such a wrapper. Its known limitations are that a) the :n and :p (next/previous file) commands in less don't work -- all the files from the command line are concatenated in a single stream, and b) It isn't able to cope with null bytes in input, unless /usr/bin/awk is actually gawk (GNU Awk) or Thomas Dickey's mawk.

#! /usr/bin/awk -f
BEGIN { "tput lines" | getline max; max -= 2 }
{ l[NR]=$0 }
NR>=max {
        for(i = 1; i <= NR; i++) print l[i] | "less";
        while(getline > 0) print | "less";
}
END { if (NR < max) for(i = 1; i <= NR; i++) print l[i] | "less -FX" }
4
  • Note that @ThomasDickey's mawk also supports NUL bytes. Sep 6, 2018 at 14:57
  • Not the mawk installed on my system (debian stretch) $ printf "a\0b" | gawk '{print}' ab $ printf "a\0b" | mawk '{print}' a
    – user313992
    Sep 6, 2018 at 15:04
  • Yes, Debian still uses the ancient one from 1996, not @ThomasDickey's one. Sep 6, 2018 at 15:05
  • At the time of writing, less 551-1~bpo10+1 is in buster-backports. backports.debian.org/Instructions
    – boltronics
    Mar 13, 2020 at 12:18
3

There's no easy way around that.

Either you let less use the alternate screen to leave the original one pristine or you don't (use -X).

You can't really expect less to restore the screen as it was and start using the alternate screen after it has read a full page.

We'd need somehow to wait until at least one page or eof has been read before starting less in the right mode and send the data. Something like:

page_stdin() {
  awk -v l="${LINES:=$(tput lines)}" '
    cmd {print | cmd; next}
    {lines = lines $0 ORS}
    NR == l {cmd = "less"; printf "%s", lines | cmd}
    END {if (!cmd) printf "%s", lines | "less -FX"}'
}
mypager() {
  if [ "$#" -eq 0 ]; then
    page_stdin
  else
    for file do page_stdin < "$file"; done
  fi
}

(with GNU awk, you can replace ORS with RT to not add a trailing newline if it wasn't there in the first place).

But that means that you won't start seeing the output of the piped command in cmd | mypager until there's a full page worth of it or it finished outputting. (try for instance seq 200 | pv -qL40 | mypager compared to seq 200 | pv -qL40 | less).

Note that it assumes you don't use things like LESS=-s and would be fooled by lines larger than the screen unless you have LESS=-S.

2

Paste that on your terminal (or put it on bashrc):

less_cat(){
     [ "$(wc -l <"$1")" -ge "$LINES" ] && less "$1" || less -FX "$1"
}

Now you should be able to execute:

less_cat /etc/fstab
less_cat /var/log/messages 

And it will do exactly what you want.

NOTE: This solution is compatible with BASH/ZSH(see the comments)

Good lucky!

9
  • 1
    Not all shells set $LINES. dash or yash don't for instance. Sep 6, 2018 at 14:08
  • 2
    You may still want to use less -X instead of cat for short inputs for its ability to render unprintable characters in a useful way. Sep 6, 2018 at 14:23
  • 1
    It's a matter of taste. But compare printf 'a\200b' | less -FX with printf 'a\200b' | cat -v Sep 6, 2018 at 14:27
  • 1
    I would use a if statement instead of a && b || c here because if b returns with a non-zero exit status, c would be run. Sep 6, 2018 at 14:53
  • 1
    Thanks :-). Yes, that would be me Sep 6, 2018 at 16:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .