我正在创建这个函数,在文件的每一行上创建多个grep。我运行如下:
cat file.txt | agrep string1 string2 ... stringN
function agrep () {
for a in $@; do
cmd+=" | grep '$a'";
done ;
while read line ; do
eval "echo "\'"$line"\'" $cmd";
done;
}
我们的想法是打印包含所有字符串的每一行:string1
,string2
,...,stringN
。这已经有效,但我想避免使用for
来构造表达式:
| grep string1 | grep string2 ... | stringN
如果可能,也使用eval
。我尝试进行如下扩展:
echo "| grep $"{1..3}
我得到了:
| grep $1 | grep $2 | grep $3
这几乎是我想要的,但问题是当我尝试时:
echo "| grep $"{1..$#}
由于{1..$#}
由于bash无法扩展$#
,因此无法进行扩展。它只适用于数字。我想构建一些有效的扩展,以避免在for
函数中使用agrep
。
答案 0 :(得分:5)
agrep () {
if [ $# = 0 ]; then
cat
else
pattern="$1"
shift
grep -e "$pattern" | agrep "$@"
fi
}
答案 1 :(得分:3)
不是在每一行上运行每个多个grep
,而是获取与string1
匹配的所有行,然后将其grep
传递给string2
,等等。这样做的方法是使agrep
递归。
agrep () {
if (( $# == 0 )); then
cat # With no arguments, just output everything
else
grep "$1" | agrep "${@:2}"
fi
}
它不是最有效的解决方案,但它很简单。
(请务必注意Rob Mayoff's answer,这是符合POSIX标准的版本。)
答案 2 :(得分:2)
awk
救援!
你可以通过切换到awk来避免多个grep调用和构造命令
awk -v pat='string1 string2 string3' 'BEGIN{n=split(pat,p)}
{for(i=1;i<=n;i++) if($0!~p[i]) next}1 ' file
输入您的空格分隔字符串,如上例所示。
答案 3 :(得分:2)
不为命令构建字符串肯定更好(请参阅chepner's和Rob Mayoff's答案)。但是,举个例子,您可以使用for
:
printf
agrep () {
cmd=$(printf ' | grep %q' "$@")
sh -c "cat $cmd"
}
使用printf
也有助于模式中的特殊字符。来自help printf
:
In addition to the standard format specifications described in printf(1),
printf interprets:
%b expand backslash escape sequences in the corresponding argument
%q quote the argument in a way that can be reused as shell input
%(fmt)T output the date-time string resulting from using FMT as a format
string for strftime(3)
由于%q
的目标是提供适合shell输入的输出,这应该是安全的。
另外:您几乎总是希望"$@"
使用引号,而不仅仅是$@
。