Bash 将任意命令通过管道传递给 less 的别名

Bash alias to pipe an arbitrary command to less

简而言之shell 我正在努力让 Perforce 工作起来更少。目前,诸如 p4 diff 之类的命令会愉快地将 5000 行转储到控制台。我希望像这样的命令能够自动输入 less 而无需我输入它(你知道,就像 g*t 那样)。

我目前最好的两个"solutions":

"Solution" 1 - A bash 函数

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

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

问题在于 Perforce 语法与 Unix shell 语法重叠。 即 p4 jobs ...@\>2015/01/20 会因为 > 符号而严重失败。

"Solution" 2 - 具有不同名称的函数

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

这很蹩脚,因为现在我必须记住键入 p4d 而不是 p4 diff,并且出于与解决方案 1 相同的原因,不适用于 p4 diff2

是否有任何 shell 或 Perforce 技巧可以让我使用 p4 diff 之类的命令通过管道传输到 less 而无需记住一直输入它?

有没有一种方法可以安全地包装 p4 参数 ($@),这样 shell 像 > 这样的符号就不会被重新解释,而是 |是?

不必是 bash。如果你有一些来自 60 年代的时髦 shell 解决了我的问题,让我们听听吧!

感谢您的帮助。

Eval 类型的解决方案通常不能很好地应对其中包含奇数字符的参数。另一方面,它们通常是不必要的。

而不是

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

有引号错误($@ 周围的引号实际上未引号 $@ 尽管修复它无济于事,因为您实际上需要在传递给 [=19 的字符串中插入转义符=]),直接执行命令即可:

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

需要定义$pager;你可能想要:

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

显式路径有点烦人。使用 bash,您可以使用 command 内置函数使它更健壮:

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

这引入了少量的重复代码,如果您要在不同的地方使用被截断的代码,那么它会有点多。您可以定义以下函数(例如,在您的 ~/.bashrc 文件中):

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

那么您的 p4 脚本可以是:

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

还有很多其他变体。注意在page函数中使用"${pager[@]}";这允许 pager 成为一个数组,以防你想将参数传递给 less。例如:

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

(括号是为了使 pager 的设置成为局部的;您不能对数组使用正常的 var=value command 语法。)

我对如何实现 p4 功能的建议:

function p4() {
    if [[  == diff ]]; then
        command p4 "$@" | less
    else
        command p4 "$@"
    fi
}

这将消除您遇到的引用和转义问题。

如果管道连接到 cat 没问题,您可以消除重复的 command p4 "$@" 部分(当 stdout 连接到 TTY 和管道时,某些命令的行为会有所不同;我不知道是否强制关心):

function p4() {
    command p4 "$@" | if [[  == diff ]]; then less; else cat; fi
}