1

我经常发现自己经常做这样的事情:

something | grep cat | grep bat | grep rat

当我记得这三个词一定是在某个地方以某种顺序出现在something...的输出中时,我可以做这样的事情:

something | grep '.*cat.*bat.*rat.*'

但这意味着排序(蝙蝠出现在猫之后)。因此,我正在考虑在我的环境中添加一个 bash 函数,称为mgrep

mgrep cat bat rat

进入

grep cat | grep bat | grep rat

但我不太确定该怎么做(或者是否有替代方案?)。一种想法是对参数进行循环,如下所示:

while (($#)); do
    grep $1 some_thing > some_thing
    shift
done
cat some_thing

其中 some_thing 可能是一些 fifo,就像>(cmd)在 bash 中那样,但我不确定。一个人将如何进行?

4

3 回答 3

2

我相信您可以通过在每一步重定向标准输入来一次生成一个命令。但是将管道生成为字符串并使用 eval 执行它更简单、更清晰,如下所示:

CMD="grep '$1' "  # consume the first argument
shift

for arg in "$@"   # Add the rest in a pipeline
do
  CMD="$CMD | grep '$arg'"
done
eval $CMD

这将生成一个始终从标准输入读取的 grep 管道,就像在您的模型中一样。请注意,它保护引用参数中的空格,以便在您编写时它可以正常工作:

mgrep 'the cat' 'the bat' 'the rat'
于 2012-09-08T21:18:52.800 回答
2

感谢亚历克西斯,这就是我所做的:

function mgrep() #grep multiple keywords
{
    CMD=''
    while (($#)); do
        CMD="$CMD grep \"$1\" | "
        shift
    done
    eval ${CMD%| }
}
于 2012-09-08T21:27:27.283 回答
1

你可以写一个递归函数;我对基本情况不满意,但我想不出更好的情况。只需要调用来将标准输入传递给标准输出似乎是一种浪费cat,而 while 循环有点不雅:

mgrep () {
    local e=$1;
    # shift && grep "$e" | mgrep "$@" || while read -r; do echo "$REPLY"; done
    shift && grep "$e" | mgrep "$@" || cat

    # Maybe?
    # shift && grep "$e" | mgrep "$@" || echo "$(</dev/stdin)"
}
于 2012-09-08T21:43:23.743 回答