Since less 530 (released in December 2017), less --quit-if-one-screen
does not switch to the alternate screen if it reads less than one screenful. So you won't have this problem if your version of less is recent enough.
In earlier versions, less has to decide whether to use the alternate screen when it starts. You can't defer that choice to when it terminates.
You could call less, let it use the alternate screen, and cat the content onto the primary screen if less terminates automatically. However I don't know of a way to detect automatic termination.
On the other hand, it isn't that difficult to call cat for short inputs and less for larger inputs, even preserving buffering so that you don't have to wait for the whole input to start seeing stuff in less (the buffer may be slightly larger — you won't see anything until you have at least one screenful of data — but not much more).
#!/bin/sh
n=3 # number of screen lines that should remain visible in addition to the content
lines=
newline='
'
case $LINES in
''|*[!0-9]*) exec less;;
esac
while [ $n -lt $LINES ] && IFS= read -r line; do
lines="$lines$newline$line"
done
if [ $n -eq $LINES ]; then
{ printf %s "$lines"; exec cat; } | exec less
else
printf %s "$lines"
fi
You might prefer to see the lines on the main screen as they come in, and switch to the alternate screen if the lines would cause scrolling.
#!/bin/sh
n=3 # number of screen lines that should remain visible in addition to the content
beginning=
newline='
'
# If we can't determine the terminal height, execute less directly
[ -n "$LINES" ] || LINES=$(tput lines) 2>/dev/null
case $LINES in
''|*[!0-9]*) exec less "$@";;
esac
# Read and display enough lines to fill most of the terminal
while [ $n -lt $LINES ] && IFS= read -r line; do
beginning="$beginning$newline$line"
printf '%s\n' -- "$line"
n=$((n + 1))
done
# If the input is longer, run the pager
if [ $n -eq $LINES ]; then
{ printf %s "$beginning"; exec cat; } | exec less "$@"
fi
Less can determine if it has been given a directory. Set the LESSOPEN
environment variable to ~/bin/LESSPIPE
and make ~/bin/LESSPIPE
a script like the following:
#!/bin/sh
if [ -d "$1" ]; then
exec /bin/ls -la "$1"
elif [ -f "$1" ]; then
case "$1" in
*.tar|ztar) exec tar tvvf "$1" 2>/dev/null;;
*.tar.[dg]z|*.tar.z|*.tgz) exec gzip -dc "$1" | tar tvvf - 2>/dev/null;;
*.tar.bz2) exec bzip2 -d <"$1" 2>/dev/null | exec tar tvvf - 2>/dev/null;;
*.tar.Z|*.taz) exec uncompress -c "$1" | exec tar tvvf - 2>/dev/null;;
*.zip) exec unzip -l "$1" 2>/dev/null;;
*.lha) exec lha -v "$1" 2>/dev/null;;
*.7z) exec 7z l "$1" 2>/dev/null;;
*.[rs]pm) exec rpm -qilp "$1";;
*.z|*.[dg]z) exec gzip -dc "$1" 2>/dev/null;;
*.bz2) exec bzip2 -dc "$1";;
*.xz) exec xz -dc "$1";;
*.Z) exec uncompress -c "$1" 2>/dev/null;;
esac
fi
You'll get a listing for directories and archives.
You can use lesskey
instead of the environment variable to set the preprocessor. See the documentation for details.
Best Answer
I don't think there's a direct method, but you can hack your way around. The following command will pipe everything from the first line on the screen to the end of the file to
grep -c ... | less
, opening a new instance ofless
to show the output ofgrep
, which will be the number of lines matching the pattern:When you quit this
less
, you'll be back to the firstless
.Other tricks:
&pattern
and then pipe towc -l
usingg|$
like above, to useless
's pattern matching10n
x times until it fails, then proceed by y single steps to get 10x+y matches).