如何将bash函数的参数扩展为一系列管道命令?

时间:2012-09-08 20:57:00

标签: bash unix grep

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

something | grep cat | grep bat | grep rat

当我回忆起这三个词必定出现在something的输出中的某个顺序时......现在,我可以这样做:

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

但这意味着订购(蝙蝠出现在猫之后)。因此,我考虑在我的环境中添加一个名为mgrep的bash函数,该函数将转为:

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,比如在bash中>(cmd)但是我不确定。如何进行?

3 个答案:

答案 0 :(得分:2)

我相信你可以一次生成一个管道命令,通过在每一步重定向stdin。但是将管道生成为字符串并使用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

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

mgrep 'the cat' 'the bat' 'the rat'

答案 1 :(得分:2)

感谢Alexis,这就是我所做的:

function mgrep() #grep multiple keywords
{
    CMD=''
    while (($#)); do
        CMD="$CMD grep \"$1\" | "
        shift
    done
    eval ${CMD%| }
}

答案 2 :(得分: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)"
}