1

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
    Have you tried with just -F? -X seems to do skip terminal initialization, so maybe that's why it leaves the screen garbled. – Mr Shunz Sep 6 '18 at 12:29
1

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!

  • 1
    Not all shells set $LINES. dash or yash don't for instance. – Stéphane Chazelas Sep 6 '18 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. – Stéphane Chazelas Sep 6 '18 at 14:23
  • 1
    It's a matter of taste. But compare printf 'a\200b' | less -FX with printf 'a\200b' | cat -v – Stéphane Chazelas Sep 6 '18 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. – Stéphane Chazelas Sep 6 '18 at 14:53
  • 1
    Thanks :-). Yes, that would be me – Stéphane Chazelas Sep 6 '18 at 16:10
2

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.

1

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.

I don't think that's possible without writing a wrapper for "less". I would like to be proved wrong, because I had the same problem as you in the past, and I even tried to modify the "less" source code for that, but the changes needed proved to be quite invasive.

Here is small example wrapper, but notice that the :n :p (next/previous file) commands in less don't work -- all the files from the command line are concatenated in a single stream. It also isn't able to cope with null bytes in input, unless /usr/bin/awk is actually gawk (GNU Awk).

#! /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" }
  • Note that @ThomasDickey's mawk also supports NUL bytes. – Stéphane Chazelas Sep 6 '18 at 14:57
  • Not the mawk installed on my system (debian stretch) $ printf "a\0b" | gawk '{print}' ab $ printf "a\0b" | mawk '{print}' a – mosvy Sep 6 '18 at 15:04
  • Yes, Debian still uses the ancient one from 1996, not @ThomasDickey's one. – Stéphane Chazelas Sep 6 '18 at 15:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.