为什么历史需要 grep 的数值?

Why does history require a numeric value for grep?

我正在尝试创建一个自定义函数 (hisgrep) 以从历史记录中进行 grep。

我以前用过它,当时代码基本上是 "history | grep ",但我希望实现能够 grep 多个关键字。 (例如 "hisgrep docker client" 等于 "history | grep docker | grep client")。

我的问题是,当我尝试执行此操作时出现此错误:“-bash:历史记录:|:需要数字参数。”

我试过将命令的调用方式从 $cmd 更改为仅 $cmd,但没有任何效果。

代码如下:

#!/bin/bash

function hisgrep() {
    cmd='history'
    for arg in "$@"; do
        cmd="$cmd | grep $arg"
    done
    `$cmd`
}

它不起作用,因为 | 被解释为 history 命令的参数。

遗憾的是,bash 没有所谓的 "foldl" 或类似功能。

你可以这样做:

histgrep() {
    local str;
    # save the history into some list
    # I already filter the first argument, so the initial list is shorter
    str=$(history | grep -e "");
    shift;
    # for each argument
    for i; do
       # pass the string via grep
       str=$(<<<"$str" grep "$i")
    done
    printf "%s\n" "$str"
}

备注:

  • 执行 cmd="$cmd | grep $arg" 然后执行 `$cmd` 看起来不安全。
  • 记得引用你的变量。
  • 使用 https://www.shellcheck.net/ 检查您的脚本。
  • 反引号 ` 是 deprecated。使用 $() 命令替换。
  • 同时使用函数和括号 function func() 不可移植。就做 func().

至于不安全的版本,您需要通过 eval 传递它(evalevil),通过智能使用 printf 缩短为:

histgrep() { eval "history $(printf "| grep -e '%s' " "$@")"; }

但我认为我们可以通过在 eval 调用中扩展命令替换后的参数来做一些更安全的事情:

histgrep() { eval "history $(printf '| grep -e "$%s" ' $(seq $#))"; }

这里的eval会看到history | grep -e "" | grep -e "" | ...我觉得其实挺安全的