2

From a script, I want to invoke less on a file and have it print the output to the console, rather than a new screen. If the file is short enough to fit on one screen, I want to disable scrolling. If it's longer than one screen, I want to be able to scroll through it, but once I hit the bottom, I want less to return control to the console. Lines should also be chopped (it's okay to lose the end of the strings past the console window in this case).

I also would like it to highlight a certain pattern.

Here is what I'm using for arguments:

less -SFXE -p "ccc" fileToShow.txt

I use -S to chop long lines, -FX to detect if the file has less lines than the console and print all the text to the console without scrolling, and -E to quit less when I've reached the end of the file, for the cases when the text is longer than the console and I need scrolling.

These work well until I add the -p switch for highlighting matches.

Suppose fileToShow.txt contains this:

aaa
bbb
ccc
ddd
eee

Without the pattern switch, I get this:

[evan@localhost] $ less -SFXE fileToShow.txt
aaa
bbb
ccc
ddd
eee
[evan@localhost] $ 

When I add the pattern matching, less prints out the empty lines up to the console height (using tildes to show the empty lines).

[evan@localhost] $ less -SFXE -p "ccc" fileToShow.txt
ccc
ddd
eee
~
~
~
~
~
~
~
~
[evan@localhost] $ 

Is there any way to use the -p switch and not have it show those empty lines when using -F? (Note: the "ccc" line is highlighted as desired, I just have this unintended side effect.)

My shell is bash 3.2.25 and my less version is 436. OS is RHEL.

4
  • I suppose -p not only searches and highlights patterns, but also moves the cursor to the first match. I think that the cursor moving part is what causes less to show those empty lines. Is there a way to get the highlighting without moving the cursor?
    – tomocafe
    Commented Aug 5, 2015 at 22:20
  • 1
    The following could be encapsulated in a batch file: grep --color=always -E "^|$2" "$1"|less -SFXER, where $1 is the file name and $2 is the search pattern. Not exactly neat, but some sort of answer. Note that this would list all the lines, highlighting the pattern, whereas less -p omits lines ahead of the first match: to do this you would need to use sed.
    – AFH
    Commented Aug 5, 2015 at 22:57
  • Yes, that works perfectly for me. If you'd like to paste it to an answer, I'd be happy to accept it.
    – tomocafe
    Commented Aug 5, 2015 at 23:27
  • Upstream issue: github.com/gwsw/less/issues/28 Commented Feb 17, 2021 at 17:50

3 Answers 3

2

The following command could be encapsulated in a batch file:

 grep --color=always -E "^|$2" "$1"|less -SFXER

The parameter $1 is the file name and $2 is the search pattern. Points to note:

  • grep -E (or egrep) allows matching to more than one search pattern;
  • matching to ^ (start of line) ensures that every line is listed;
  • matching $2 causes the search string to be highlighted;
  • grep --color=always copies the highlighting escape sequences to the pipe;
  • less -R makes less reproduce the highlighting instead of showing the escape sequence.

It is not the neatest of solutions, but some sort of answer. Note that the command will list all the lines, highlighting the pattern, whereas less -p omits lines ahead of the first match: to reproduce this you would need to use sed.

2

There's another way, all in less. It involves a few steps, though.

  1. less fileToShow.txt
  2. Hit &ccc (assuming ccc is the pattern you're looking for). From the man page:

    &pattern: Display only lines which match the pattern; lines which do not match the pattern are not displayed. If pattern is empty (if you type & immediately followed by ENTER), any filtering is turned off, and all lines are displayed. While filtering is in effect, an ampersand is displayed at the beginning of the prompt, as a reminder that some lines in the file may be hidden. Certain characters are special as in the / command: ^N or ! Display only lines which do NOT match the pattern. ^R Don't interpret regular expression metacharacters; that is, do a simple textual comparison.

  3. Finally, press F to resume tailing
3
  • Cool! It's possible to use + flag to pass initial keystrokes to less. You need a newline char to actually execute the filtering; escaping syntax depends on shell, in bash less $'+&ccc\n', in fish less +\&ccc\n. Commented Feb 17, 2021 at 8:10
  • To exit the filtering and show all lines, type & followed by Enter (empty filter). Commented Feb 17, 2021 at 8:11
  • This answer is not quite what OP wanted though — it omits lines that don't match. Commented Feb 17, 2021 at 8:28
1

Not entirely a solution, but some improvements over -p...
These rely on the flexible + flag:

If a command line option begins with +, the remainder of that option is taken to be an initial command to less. For example, +G tells less to start at the end of the file rather than the beginning, and +/xyz tells it to start at the first occurrence of "xyz" in the file. As a special case, +<number> acts like +<number>g; that is, it starts the display at the specified line number (however, see the caveat under the "g" command above). If the option starts with ++, the initial command applies to every file being viewed, not just the first one. The + command described previously may also be used to set (or change) an initial command for every file.

-p skips to the first match (or a few lines before it if you use --jump-target). This is not what I'd want combined with exiting when short — the skipped lines are not even terminal's scrollback!

  1. If you launched less then searched interactively /ccc, less would first display lines from the start and only then scroll, so they would become part of terminal's scrollback buffer. We can emulate that using + but we need to explicitly request a re-paint with r:

    env LESS= less -SFXE +r/ccc fileToShow.txt
    

    This still scrolls to the ccc line, but now aaa and bbb are at least in the scroll-back buffer. However if the search skips a lot of lines:

    seq 1000 | less -SFXE +r/980
    

    the scrollback will show something like:

     48
     49
     50
     ...skipping...
     980
     981
     982
    

    I expected this will be tunable by --max-back-scroll, but it doesn't seem to affect search. EDIT: it seems to depend on window size, i.e. it fills one screen, then skips.

  2. Who said I don't want to see the first lines? If I only want to highlight matches, I could use the empty-match trick:

     less -SFXE '+r/ccc|$' fileToShow.txt
    

    but this breaks navigation with n/N. It's better to use this flag on / search:

    Certain characters are special if entered at the beginning of the pattern; they modify the type of search rather than become part of the pattern:
    ...

    • ^K Highlight any text which matches the pattern on the current screen, but don't move to the first match (KEEP current position).

    The syntax to include Ctrl+K char depends on the shell, in bash this works:

     less -SFXE $'+r/\cKccc' fileToShow.txt
    

    Either way, starting from first line also reduces the number of ~ filling the screen 👍.

  3. Another benefit of the +r/PATTERN approach is what happens when there is no match. -p shows annoying Pattern not found (press RETURN) prompt before displaying anything 🙈 [tracked in https://github.com/gwsw/less/issues/135].

    With +r/, the first page is printed first, then the prompt is shown. It still requires interactive Enter to confirm, even when the result fits on one screen 🙁.

[I'm using less 551.]

You must log in to answer this question.

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