less -M will show the file name as a prompt, as in:

      1 asdf
test.txt lines 1-1/1 (END)

I like to pipe grep into less for easier reading. Can I get less to interpret the grep command as file name for its prompt?

Normally it's just:

grep asdf test.txt | less :

      1 asdf
lines 1-1/1 (END)

I'd like:

grep asdf test.txt | less :

      1 asdf
grep asdf test.txt lines 1-1/1 (END)

I know I could wrap this all in a script and do things with the $0 arguments but not trying to reinvent the wheel here.

Is this possible with just a couple command line tricks?

  • grep -H? Isn't it misleading to show the filename anyway, since it's only grep's output... – Xen2050 Dec 12 '17 at 19:24
  • I wanted the "file name" as interpreted by less -M to be the grep command used; in my example the command was grep asdf text.txt which would show as the file name in less, just as a simple reminder of what I looked for in the first place. – Mike Dannyboy Dec 13 '17 at 1:50

less has not a clue as to what is on the other side of the pipe that is feeding data to it via standard input, unless someone greatly complicates the code for less to find the process group that less is running in and other processes in that process group and then who knows how those all fit together (the shell knows this information but may not make it available).

From some reading in less(1) one may find the -P option to customize the prompt

$ echo hi | less -P '?f%f:Standard input'
Standard input

so in theory if we can replace the Standard input bit with the current shell pipeline...let's see what is set when less is run...

$ function less { set > whatisset; command less "$@"; }
$ echo foo | less
$ egrep 'echo|foo' whatisset

so nothing obvious to use for mksh, as echo or foo (equivalent to your grep) do not appear anywhere in the shell environment (same story for zsh and oh wow does bash on Linux ever spam the environment with settings but again same story). Actually, with zsh we can use a preexec function to make the command line available:

$ zsh
% function preexec { shift; SHORT=$1; }
% function less { set > whatisset; command less "$@"; }
% echo foo | less
% grep SHORT whatisset
SHORT='echo foo | less'

so one could do something like

% less() { =less -P '?f%f:'${SHORT%% | less} "$@"; }
% echo hi|less
echo hi
  • Cool thanks. So it seems the long and short of it is it can be done in zsh but not so easily in bash. As I thought, nothing simply. Thanks for detailed answer though, always great to learn new things. – Mike Dannyboy Dec 13 '17 at 1:47

I went against myself and wrote a little script that accomplishes this. It's not pretty but it works, and not bad as it's only a few lines. Always up for improvements.


# store all args as string

# create temp file named as grep command
TMPFILE=$(mktemp -q "$allargs")

# run grep command
$* --color=always > "$TMPFILE" # --color=always with less -r will highlight results in less

# show results file in less
less -Mr "$TMPFILE"

# delete the temp file
rm -f -- "$TMPFILE"

Run as ./scriptname grep <opts> <regex> <file(s)>.

Downside: if file is * (search all in current dir) then they are expanded and made as part of the file name which defeats the purpose as it pushes the command off the screen (very long file name). Unless there's a way to scroll the file name horizontally in less?

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.