我想将多个模式传递给grep
,并且有许多关于如何将-e
选项应用于每个模式的解决方案。
不同的模式存储在数组中ptrn
。我想知道数组元素中的空白是否会被误解,因为它们-e
不会单独传递给模式。
可能性是
可能性1
mptrn=$( printf -- ' -e %s' "${ptrn[@]}" )
grep -E "$mptrn" -- "$flnm"
可能性2
for i in "${!ptrn[@]}"; do
ptrn[$i]="-e ${ptrn[$i]}"
done
grep -E "${ptrn[@]}" -- "$flnm"
可能性3
eptrn=()
for i in "${!ptrn[@]}"; do
eptrn+=("-e" "${ptrn[$i]}")
done
grep -E "${eptrn[@]}" -- "$flnm"
任何解决方案可能存在哪些问题?
答案1
这么说吧ptrn=(" a b" " 333 22 1 ")
。
答案1:
mptrn=$( printf -- ' -e %s' "${ptrn[@]}" )
grep -E "$mptrn" -- "$flnm"
该命令的整个输出将被分配给mptrn
,并且如果数组中的元素包含空格字符,则使用的格式将不允许区分它们。mptrn
将包含-e a b -e 333 22 1
(带有前导和尾随空格字符)。执行时grep
,由于前导空格,带引号的参数将被解释为模式参数,它将搜索给"$mptrn"
定文件中出现的 ,这不是您想要实现的目标。要使类似的方法发挥作用,您可以使用IFS
范围。
[ "${IFS+x}" = x ] && OLD_IFS=$IFS
IFS=$(printf '\x7f')
mptrn=$(printf "-e${IFS}%s${IFS}" "${ptrn[@]}")
# note that we don't use quotes
grep -E $mptrn -- "$flnm"
if [ "${OLD_IFS+x}" = x ]; then IFS=$OLD_IFS; else unset IFS; fi
答案2:
for i in "${!ptrn[@]}"; do
ptrn[$i]="-e ${ptrn[$i]}"
done
grep -E "${ptrn[@]}" -- "$flnm"
这个答案接近于期望的结果,除了搜索的模式将包含前导空格,这意味着生成的命令如下所示:
grep -E "-e a b" "-e 333 22 1 " -- file
只需删除空格即可解决此问题:ptrn[$i]=-e${ptrn[$i]}
。
答案3:
eptrn=()
for i in "${!ptrn[@]}"; do
eptrn+=("-e" "${ptrn[$i]}")
done
grep -E "${eptrn[@]}" -- "$flnm"
这个答案是正确的,生成的grep
命令将是:
grep -E -e " a b" -e " 333 22 1 " -- file
答案2
将它们组合成一个正则表达式。例如,如果您想匹配任何模式,您可以使用正则表达式交替运算符|
作为 OR。
首先,join_by
在 bash 中创建一个函数:
join_by () {
local d="$1";
shift;
printf '%s' "$1";
shift;
printf '%s' "${@/#/$d}"
}
perl
这是的内置函数的相当简单的克隆join
。它使用第一个参数作为分隔符,然后使用该分隔符连接所有剩余的参数,而无需额外烦人的前导或尾随分隔符。
然后像这样使用它:
$ p=(a b c d e)
$ re=$(join_by '|' "${p[@]}")
$ echo $re
a|b|c|d|e
您可以使用 $re grep -E
(替换需要扩展正则表达式,“ERE”)。
grep -E "$re" filename
如果您需要执行更复杂的布尔运算(例如a && b && ! (c || d || e
),请使用 perl 或 awk。 bash 是数据处理语言的糟糕选择。