2

When I pipe something into less --quit-if-one-screen +G (alias -F +G), less opens and scrolls to the end if the output exceeds the terminal size.

Unfortunately, it also scrolls to the end before closing and with that occupies a whole terminal screen, which looks something like this (if the terminal has 6 lines):

❯ echo hi | less --quit-if-one-screen +G
~
~
~
~
~
hi

Is there a way to prevent this, i.e. preserve input untouched if it is less than one page but scrolling to the end if it is.

1 Answer 1

1

I think the only way to do it would be to use separate commands depending on what you're passing it.

First of all, for easy demonstration, I'll create two variables, one containing 4 lines of text, the other containing 20 lines of text.

SmallVar=$(cat <<EOF
01 SmallVar
02 A
03 B
04 C
EOF
)
LargeVar=$(cat <<EOF
01 LargeVar
02 A
03 B
04 C
05 D
06 E
07 F
08 G
09 H
10 I
11 J
12 K
13 L
14 M
15 N
16 O
17 P
18 Q
19 R
20 S
EOF
)

echo
echo "Lines in SmallVar: $(echo "${SmallVar}" | wc -l)"
echo "Lines in LargeVar: $(echo "${LargeVar}" | wc -l)"
echo "Lines available in terminal: $(tput lines)"
echo

The output of the above is:

Lines in SmallVar: 4
Lines in LargeVar: 20
Lines available in terminal: 15

These are all on one line, but could be split to multiple for easy reading. tmpVar is the variable or file content you're passing. (if you're passing a file content, you can use tmpVar="$(cat filename.txt")

Short List

tmpVar="${SmallVar}"; if [ $(echo "${tmpVar}" | wc -l) -le $(tput lines) ]; then echo "${tmpVar}" | less -FX; else echo "${tmpVar}" | less +G -FX; fi;

Long list

tmpVar="${LargeVar}"; if [ $(echo "${tmpVar}" | wc -l) -le $(tput lines) ]; then echo "${tmpVar}" | less -FX; else echo "${tmpVar}" | less +G -FX; fi;

It is probably easier to read it split into separate lines:

tmpVar="${SmallVar}";
#tmpVar="${LargeVar}";
if [ $(echo "${tmpVar}" | wc -l) -le $(tput lines) ];
then
    echo "${tmpVar}" | less -FX;
else
    echo "${tmpVar}" | less +G -FX;
fi;

First it does an if to compare the number of lines in the variable against the number of lines in the terminal (run tput lines on its own, resize the window and run again). If it's equal-to or less than, it ignores the +G. Otherwise, it'll use the +G. The -X is used to leave the values on screen after it exits. When you press q to quit, it keeps the last few lines on screen without clearing them.

Compare

$ tmpVar="${SmallVar}"; if [ $(echo "${tmpVar}" | wc -l) -le $(tput lines) ]; then echo "${tmpVar}" | less -FX; else echo "${tmpVar}" | less +G -FX; fi;
01 SmallVar
02 A
03 B
04 C
$ 

with

$ tmpVar="${LargeVar}"; if [ $(echo "${tmpVar}" | wc -l) -le $(tput lines) ]; then echo "${tmpVar}" | less -FX; else echo "${tmpVar}" | less +G -FX; fi;
...........[scroll]...........
07 F
08 G
09 H
10 I
11 J
12 K
13 L
14 M
15 N
16 O
17 P
18 Q
19 R
20 S
(END)

 
5
  • I presumed you're doing this in a script, so a little extra processing shouldn't be a deal-breaker, but if you're manually typing -F +G or worse --quit-if-one-screen +G, my answer won't help as it's far too long, sorry. If you don't mind not being able to scroll back, but want to get say the last X lines, you could use ls -l /etc | tail -n X.
    – Aubs
    Dec 18, 2022 at 12:15
  • There is another crucial problem: Your answer executes the command multiple times, which can add a delay if it is expensive. I think if the output is saved to a variable first, this could make sense for scripts.
    – xeruf
    Dec 19, 2022 at 17:28
  • Sorry, I'm not sure I follow. I could only give examples using likely small/large directories, so used /var & /etc. The command that gives you the lines of text (it could be a text file) would need to go in the tmpVar variable, e.g. tmpVar="cat somefile". This is collected once. Then if [ $($tmpVar | wc -l) -le $(tput lines) ] checks how many lines are in the variable, if it is less than the number of rows in the terminal, it'll run the first command then $tmpVar | less -FX, otherwise (i.e. there's more than the screen fits) it'll run the second command else $tmpVar | less +G -FX.
    – Aubs
    Dec 19, 2022 at 19:51
  • $tmpVar contains the command, not the content, and you are executing the command at least 2 times
    – xeruf
    Dec 20, 2022 at 1:06
  • 1
    @xeruf you're absolutely right, sorry, I'm such an idiot. Completely re-written the answer to give a fuller response.
    – Aubs
    Dec 21, 2022 at 22:24

You must log in to answer this question.

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