![使用 awk 或 sed 从文件中提取多个信息](https://linux22.com/image/157841/%E4%BD%BF%E7%94%A8%20awk%20%E6%88%96%20sed%20%E4%BB%8E%E6%96%87%E4%BB%B6%E4%B8%AD%E6%8F%90%E5%8F%96%E5%A4%9A%E4%B8%AA%E4%BF%A1%E6%81%AF.png)
我有一个程序可以生成如下所示的日志文件:
Player: 9.8.7.6.5.4.3.2.1 () Item: 10/gold/tool//onehanded///, 15/gold/tool//twohanded
Player: 8.7.6.5.4.3.2.1.9 () Item: 20/diamond/tool//twohanded///
Player: 7.6.5.4.3.2.1.9.8 () Item: 30/copper/tool//onehanded///, 36/gold/tool//twohanded///
Player: 6.5.4.3.2.1.9.8.7 () Item: 40/gold/tool//twohanded///
Player: 5.4.3.2.1.9.8.7.6 () Item: 50/gold/tool//onehanded///, 55/gold/tool//twohanded///
Player: 4.3.2.1.9.8.7.6.5 () Item: 10/gold/tool//onehanded///, 12/diamond/tool//twohanded///
...
日志文件不断地出现。我需要的是打印所有的输出玩家拥有以下工具金子, 随着ID该工具的。例如,我需要这个:
Player: 9.8.7.6.5.4.3.2.1;10;15
Player: 7.6.5.4.3.2.1.9.8;36
Player: 6.5.4.3.2.1.9.8.7;40
Player: 5.4.3.2.1.9.8.7.6;50;55
Player: 4.3.2.1.9.8.7.6.5;10
正如您所看到的,玩家 8.7.6.5.4.3.2.1.9 不在输出中,因为该玩家没有黄金工具。
到目前为止我的代码如下所示:
grep "/gold" file | awk -F '[()]' '{print $1}'
产生这个:
Player: 9.8.7.6.5.4.3.2.1
Player: 7.6.5.4.3.2.1.9.8
Player: 6.5.4.3.2.1.9.8.7
Player: 5.4.3.2.1.9.8.7.6
Player: 4.3.2.1.9.8.7.6.5
我可以在上面的代码中添加什么来修复它?
答案1
使用 GNU awk:
$ gawk -F' \\(\\) ' '
/gold\/tool/ {
items = $2; ids="";
while(match(items,/([0-9]+)\/gold\/tool/,a)) {
ids = ids ";" a[1];
items = substr(items,RSTART+RLENGTH+1)
}
print $1 ids
}' file
Player: 9.8.7.6.5.4.3.2.1;10;15
Player: 7.6.5.4.3.2.1.9.8;36
Player: 6.5.4.3.2.1.9.8.7;40
Player: 5.4.3.2.1.9.8.7.6;50;55
Player: 4.3.2.1.9.8.7.6.5;10
答案2
受到 Steeldriver 的启发,也许更简单一些:
gawk '{
g=0
for (i=5; i<=NF; i++) {
if (match($i, /^([0-9]+)\/gold/, a)) {
if (g++ == 0) printf "%s %s", $1, $2
printf ";%s", a[1]
}
}
if (g > 0) printf "\n"
}' file
答案3
GNU sed 处于扩展正则表达式模式,-E
使正则表达式的编写不再那么令人畏惧。使用的方法是立即丢弃任何不感兴趣的线,即那些不包含黄金的线。之后,我们剥离所有非金牌,同时仅剥离金牌之前的数字:
$ sed -Ee '
s/\s*[(][)]\s*/\n/
\|\n.*[0-9]/gold/|!d
:a
/\n$/!{
\|\n([0-9]+)/gold/\S+\s*|{
s//;\1\n/;ba
}
s|\n\S+\s*|\n|;ba
}
s/(^\s*|\s*$)//g
' file.log
Perl 使任务变得微不足道:
$ perl -F'[(][)]' -lane '
(my $p = $F[0]) =~ s/(^\s*|\s*$)//g;
my @A = $F[1] =~ m[\D(\d+)/gold/]g;
print join ";", $p, @A if @A;
' file.log
结果:
Player: 9.8.7.6.5.4.3.2.1;10;15
Player: 7.6.5.4.3.2.1.9.8;36
Player: 6.5.4.3.2.1.9.8.7;40
Player: 5.4.3.2.1.9.8.7.6;50;55
Player: 4.3.2.1.9.8.7.6.5;10