Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash alias to pipe an arbitrary command to less

In a nutshell I'm trying to make Perforce work with less. At the moment a command such as p4 diff will happily dump 5000 lines to the console. I want commands like this to automatically pipe into less without me having to type it (you know, like g*t does).

My two best "solutions" so far:

"Solution" 1 - A bash function

function p4() {
    pager=""
    if [ "$1" = "diff" ]
    then
        pager=" | less"
    fi

    /bin/sh -c "/usr/local/bin/p4 "$@" $pager"
}

Problem with this is Perforce syntax overlaps Unix shell syntax. i.e. p4 jobs ...@\>2015/01/20 will fail horribly because of the > symbol.

"Solution" 2 - Function with a different name

function p4d() {
    p4 diff "$@" | less
}

Which is lame because now I have to remember to type p4d instead of p4 diff and won't work for p4 diff2 for the same reason as solution 1.

Are there any shell or Perforce tricks I can use to get commands like p4 diff to pipe into less without me having to remember to type it all the time?

Is there a way I can safely wrap the p4 arguments ($@) so that shell symbols like > are not reinterpreted but | is?

Does not have to be bash. If you have some funky shell from the 60s which solves my problem let's hear it!

Thank you for your help.

like image 701
user4495048 Avatar asked Jul 05 '26 14:07

user4495048


1 Answers

Eval-type solutions generally fail to be robust against arguments with odd characters in them. On the other hand, they are often unnecessary.

Instead of

/bin/sh -c "/usr/local/bin/p4 "$@" $pager"

which has a quotation error (the quotes around $@ are actually unquoting $@ although fixing that won't help since you would actually need to insert escapes into the string passed to bash -c), you can just execute the command directly:

/usr/local/bin/p4 "$@" | "$pager"

That requires that $pager be defined; you would probably want:

if [[ $pager ]]; then
  /usr/local/bin/p4 "$@" | "$pager"
else
  /usr/local/bin/p4 "$@"
fi

The explicit path is a bit annoying. With bash, you can make this more robust by using the command builtin:

if [[ $pager ]]; then
  command p4 "$@" | "$pager"
else
  command p4 "$@"
fi

That introduces a small duplication of code, and it's a bit much if you're going to use that snipped in various places. You could define the following function (in your ~/.bashrc file, for example):

page() {
  if [[ $pager ]]; then
    "$@" | "${pager[@]}"
  else
    "$@"
  fi
}

Then your p4 script could be:

p4() {
  local pager=
  if [[ $1 = diff ]]; then pager=less; fi
  page command p4 "$@"
}

There are lots of other variants. Note the use of "${pager[@]}" in the page function; this allows pager to be an array, in case you want to pass arguments to less. For example:

( pager=(less -N); p4 diff ...; )

(The parentheses are to make the setting of pager local; you can't use the normal var=value command syntax with arrays.)

like image 197
rici Avatar answered Jul 08 '26 16:07

rici



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!