Reputation: 60
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.
Upvotes: 3
Views: 1728
Reputation: 241861
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.)
Upvotes: 4
Reputation: 361889
My suggestion for how to implement your p4
function:
function p4() {
if [[ $1 == diff ]]; then
command p4 "$@" | less
else
command p4 "$@"
fi
}
This will eliminate the quoting and escaping problems you're seeing.
You could eliminate the repeated command p4 "$@"
pieces if piping to cat
is okay (some commands will behave differently when stdout is connected to a TTY vs. a pipe; I don't know if perforce cares):
function p4() {
command p4 "$@" | if [[ $1 == diff ]]; then less; else cat; fi
}
Upvotes: 3