我有一个这样的文件(这是样本):
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变量在/^ /
正则表达式块中不起作用。我怎么能这样做?
答案 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)
这是bash
,sed
和grep
的一种方式,它是直截了当的,在这种情况下,我认为可能比awk
更清洁一点:
IFS=$(echo -en "\n\b") && for ip in $(sed 's/\./\\&/g' iplist.txt); do
grep "^[^|]*|[^|]*|${ip}" r.txt
done