我经常发现自己做了很多这样的事情:
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)
但是我不确定。如何进行?
答案 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)"
}