我该如何拆分这个字符串

时间:2012-09-09 21:30:24

标签: bash awk gnu cut

我目前正在尝试清理一些日志文件,因此它们的格式更容易阅读,并且一直在尝试使用gnu cut命令,它运行得相当好,虽然我真的想不出一个好方法来删除[INFO]字符串的一部分

logs/logs/server_1283258036.log:2010-08-31 23:06:51 [INFO] <NateMar> where?!
logs/logs/server_1281904775.log:2010-08-15 22:59:53 [INFO] <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh
logs/logs/server_1282136782.log:2010-08-18 16:27:32 [INFO] <pinguin> <pinguin>§F :/
logs/logs/server_1282136782.log:2010-08-18 16:27:37 [INFO] <TotempaaltJ> <TotempaaltJ>§F That helped A LOT
logs/logs/server_1282136782.log:2010-08-18 16:27:37 [INFO] <Rizual> §b<Rizual>§F hm?
logs/logs/server_1282136782.log:2010-08-18 16:29:10 [INFO] <pinguin> <pinguin>§F bah
logs/logs/server_1282136782.log:2010-08-18 16:29:35 [INFO] <TotempaaltJ> <TotempaaltJ>§F Finished my houses 
logs/logs/server_1282136782.log:2010-08-18 16:29:40 [INFO] <TotempaaltJ> <TotempaaltJ>§F or whatever
logs/logs/server_1282136782.log:2010-08-18 16:30:47 [INFO] <Rizual> §b<Rizual>§So much iron
logs/logs/server_1282136782.log:2010-08-18 16:30:58 [INFO] <TotempaaltJ> <TotempaaltJ>§F Ah yes, furnaces don't work.o
logs/logs/server_1282136782.log:2010-08-18 16:31:01 [INFO] <Rizual> §b<Rizual>§F They do
logs/logs/server_1282136782.log:2010-08-18 16:31:06 [INFO] <TotempaaltJ> <TotempaaltJ>§F Hm
logs/logs/server_1282136782.log:2010-08-18 16:31:08 [INFO] <Rizual> §b<Rizual>§F just need to use /lighter
logs/logs/server_1282136782.log:2010-08-18 16:31:12 [INFO] <Valrix> <Valrix>§FNotch fixed them?

我最终希望将字符串分解为类似于以下内容的字符串(请记住,日志有两种格式,旧格式有两个名称副本,可以在大部分内容中看到)上面的日志,以及更新的格式,其中只有一个名称(可以在第一个日志行中看到<natemar>一个))

2010-08-31 23:06:51 <NateMar> where?!    
2010-08-15 22:59:53 <BoonTheMoon> ohhhhhh (this one would require both the same editing as above, plus removal of the "extra" name §b<BoonTheMoon>§)    

我应该怎么做呢?考虑过使用awk,虽然我很难掌握它的工作原理,所以不确定如何设置一些东西来做到这一点。任何帮助将不胜感激,谢谢!

4 个答案:

答案 0 :(得分:3)

您使用cut命令走在正确的轨道上。删除[INFO]字段的关键是将其从最终输出中排除。 -f1,2,4-参数通过包含除了之外的所有字段来实现这一点,而第三个只是[INFO]。

cut -d: -f2- Input.txt | cut -d' ' -f1,2,4- > Output.txt    

答案 1 :(得分:3)

更多信息,sed,awk和bash:

[ghoti@pc ~]$ cat text
logs/logs/server_1283258036.log:2010-08-31 23:06:51 [INFO] <NateMar> where?!
logs/logs/server_1281904775.log:2010-08-15 22:59:53 [INFO] <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

[ghoti@pc ~]$ sed 's/^[^:]*://;s/[[][^]]*[]] //' text
2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

[ghoti@pc ~]$ awk '{sub(/^[^:]+:/,""); $3=""} 1' text
2010-08-31 23:06:51  <NateMar> where?!
2010-08-15 22:59:53  <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

[ghoti@pc ~]$ while read line; do line=${line#*:}; echo "${line/\[*\] }"; done < text
2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

虽然这些很简单,但为了简洁起见,它们可能并不完美。例如,awk脚本通过消除第三个“单词”,留下用于分隔现在为空的单词的空格。

请注意,对于快速工作而言,“单线”可能看起来“优雅”,因此明确使用代码通常更好一点,特别是当您必须处理未知输入数据或者您不会检查在你运行之后立即得到结果。

这很难阅读,但可能会更安全,具体取决于您的输入:

[ghoti@pc ~]$ awk '$3~/^[[].+[]]$/{$3="";sub(/  /," ")} {sub(/^[^:]+:/,"")} 1' text
2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> çb<BoonTheMoon>çohhhhhh

对于bash脚本,使用字符类而不是glob:

会更安全
[ghoti@pc ~]$ shopt -s extglob
[ghoti@pc ~]$ while read line; do line=${line#*:}; echo "${line/\[+([[:upper:]])\] /}"; done < text
2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> çb<BoonTheMoon>çohhhhhh

请注意,extglob shopt选项允许您在参数替换模式中使用更高级的模式匹配。 man bash并查找Pathname Expansion了解详情。

<强>更新

您已经为您的问题添加了最初不存在的新要求。以下是使用awk实现新要求的方法:

awk '$3~/^[[].+[]]$/{$3="";sub(/  /," ")} {sub(/^[^:]+:/,"")} $3~/^<.+>$/{sub(/^(§b)?<[[:alpha:]]+>§/,"",$4)} 1' text

如果第三个字符串看起来像一个括号内的昵称,这只会从第四个字符串中删除彩色昵称。这适用于您发布的样本,但只有您可以确定这是否适合您。

用bash:

shopt -s extglob
while read date time tag nick line; do
  printf "%s %s %s %s\n" "${date#*:}" "$time" "$nick" "${line/#*([^< ])$nick??}"
done < text

答案 2 :(得分:2)

(根据上述评论中发布的问题的答案可能正在等待修订)

使用awk

awk '{sub(".log:", ".log "); print $2, $3, $5, $6}' data.txt

会给你:

2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

解释

我将“:”之后的.log:更改为空白,然后能够通过空格分隔行中的字段。您感兴趣的字段分别为2,3,5和6,因此我使用awk使用$将其打印出来,以获取该行中每个字段的内容。

请注意,如果需要,您还可以使用printf更精确地格式化数据。

答案 3 :(得分:1)

使用sed,可以更加努力地完成:

$> cat ./text
logs/logs/server_1283258036.log:2010-08-31 23:06:51 [INFO] <NateMar> where?!
logs/logs/server_1281904775.log:2010-08-15 22:59:53 [INFO] <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

$> sed -r -e 's/^.*log:([0-9]{4}-[0-9]{2}-[0-9]{2}\ )([0-9\ \:]*\ )(\[[A-Z]*\]\ )(.*)$/\1\2\4/' ./text
2010-08-31 23:06:51 <NateMar> where?!
2010-08-15 22:59:53 <BoonTheMoon> §b<BoonTheMoon>§ohhhhhh

整个想法是匹配日志字符串的某些字段,然后只留下您需要的字段。