如何在awk中使用bash变量和regexp?

时间:2016-03-21 09:36:00

标签: regex bash awk

我有一个这样的文件(这是样本):

71.13.55.12|212.152.22.12|71.13.55.12|8.8.8.8
81.23.45.12|212.152.22.12|71.13.55.13|8.8.8.8
61.53.54.62|212.152.22.12|71.13.55.14|8.8.8.8
21.23.51.22|212.152.22.12|71.13.54.12|8.8.8.8
...

我有这样的iplist.txt:

71.13.55.
12.33.23.
8.8.
4.2.
...

我需要grep if 3. column如iplist.txt中那样启动。

像这样:

71.13.55.12|212.152.22.12|71.13.55.12|8.8.8.8
81.23.45.12|212.152.22.12|71.13.55.13|8.8.8.8
61.53.54.62|212.152.22.12|71.13.55.14|8.8.8.8

我试过了:

for ip in $(cat iplist.txt); do
    awk -v var="$ip" -F '|' '{if ($3 ~ /^$var/) print $0;}' text.txt
done

但是bash变量在/^ /正则表达式块中不起作用。我怎么能这样做?

3 个答案:

答案 0 :(得分:3)

首先,您可以使用正则表达式的字符串串联,它不必是正则表达式块。你可以说:

'{if ($3 ~ "^" var) print $0;}'

其次,请注意,您不要在awk中使用带有变量的$$仅用于按编号引用字段(如$3$somevar,其中somevar的字段编号为其值。)

第三,你可以在awk中做所有事情,在这种情况下你可以避免shell循环而不需要var:

awk -F'|' 'NR==FNR {a["^" $0]; next} { for (i in a) if ($3 ~ i) {print;next} }' iplist.txt r.txt
71.13.55.12|212.152.22.12|71.13.55.12|8.8.8.8
81.23.45.12|212.152.22.12|71.13.55.13|8.8.8.8
61.53.54.62|212.152.22.12|71.13.55.14|8.8.8.8

修改
正如评论中正确指出的那样,模式中的.将匹配任何字符,而不仅仅是文字.。因此我们需要在进行比赛之前逃避它们:

awk -F'|' 'NR==FNR {gsub(/\./,"\\."); a["^" $0]; next} { for (i in a) if ($3 ~ i) print }' iplist.txt r.txt

我假设您只想输出一次给定的行,即使它与iplist.txt中的多个模式匹配。如果您想为多个匹配多次输出一行(正如您的版本所做的那样),请从next移除{print;next}

答案 1 :(得分:2)

直接使用var,而不是/^$var/(先将^添加到变量中):

awk -v var="^$ip" -F '|' '$3 ~ var' text.txt

顺便说一句,真实条件的默认操作是打印当前记录,因此,{if (test) {print $0}}通常可以缩减为test

答案 2 :(得分:1)

这是bashsedgrep的一种方式,它是直截了当的,在这种情况下,我认为可能比awk更清洁一点:
IFS=$(echo -en "\n\b") && for ip in $(sed 's/\./\\&/g' iplist.txt); do grep "^[^|]*|[^|]*|${ip}" r.txt done