【问题标题】:Parsing, reformating log file using sed or perhaps a script?使用 sed 或脚本解析、重新格式化日志文件?
【发布时间】:2016-01-15 12:20:47
【问题描述】:

我有一个案子,一个文件,我需要post-process。示例格式如下:-

bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
1.1.1.1 Intel::DOMAIN   from http://abcd.com/bl/BOOT via intel.criticalstack.com     F

预期输出是:--

1.1.1.1 abcd

解析为:-

  • 任何不以 IP 地址开头的内容删除该行
  • 如果以IP地址开头的话

    • 删除 Intel::DOMAIN
    • from F 之间根据以下字符串出现替换它
    • 例如 malc0de 或 abcd

我想使用 sed,但我不知道 sed 是否可用于匹配多个字符串,例如 malc0de 或 abc,也许我需要一个更完整的脚本,然后只需将字符串值存储在数组中。任何想法?顺便说一句,使用sed 的例子是最受欢迎的。

到目前为止

  • 我知道在 sed 中使用 d 可以删除该行并将输出重定向到文件
  • 我知道如何匹配非 IP 地址的正则表达式 [^a-zA-Z]
  • 我无法根据多项选择或字符串进行替换
\#!/bin/bash          
sed -i s/\[a-zA-Z]\/d test ./infile > testme.txt
sed -i s/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/s+\Intel::DOMAIN\\s*from(.*?)\s+F\1malc0de

或者我正在考虑像 ARRAY=(malc0de abcd) 一样保存

然后我可以做 ${ARRAY[2]} 代替捕获组,它会起作用吗?或者我可以做一些事情,比如在 fromF 之间的.net 子字符串匹配中,我将结果复制到字符串变量中。然后搜索我的字符串,例如malc0de,如果找到用匹配的结果替换搜索到的模式?但我不知道 bash...

更新 有了 awk 脚本,我就这么干净了

1.1.1.1 www.abc.com
1.1.2.2 def.com
2.2.2.2 mnx.dbc.net

但是,我希望将 ip 地址之后的第二列缩短为我自己选择的字符串,例如在第二列中我只接受

abc 定义 mnx

一次,它发现只是将整个字符串替换为

1.1.1.1 abc
1.1.2.2 def
2.2.2.2 mnx

谢谢。

【问题讨论】:

  • 如果您可以为给定数据提供预期输出,那么其他人就更容易理解了
  • @Marged 请参阅更新

标签: regex linux bash ubuntu sed


【解决方案1】:

试试这个小家伙:

sed -nE 's/(^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}) .* [htpsw:\/.]{4,8}([0-9a-z.]+)\.com.*$/\1 \2/p' > newfile

想法是使用分组(),定义适当的组,然后仅使用\1 \2 等将匹配的行替换为组。-n p 组合用于仅显示替换的行,并且仅在匹配模式时才替换行。如果您还想保留不匹配的行,请删除 -n p

输入文件:

bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
1.1.1.1 Intel::DOMAIN   from http://abcd.com/bl/BOOT via intel.criticalstack.com     F
bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
123.1.1.1 Intel::DOMAIN   from http://abcd12.bcd.com/bl/BOOT via intel.criticalstack.com     F
bigspeedpro.com Intel::DOMAIN   from https://malc0de.com/bl/BOOT via intel.criticalstack.com     F
87.1.4.1 Intel::DOMAIN   from http://abcdtdd.com/bl/BOOT via intel.criticalstack.com     F
bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
192.168.1.1 Intel::DOMAIN   from www.abcdbc12a.bdf12.com/bl/BOOT via intel.criticalstack.com     F

输出新文件:

1.1.1.1 abcd
123.1.1.1 abcd12.bcd
87.1.4.1 abcdtdd
192.168.1.1 abcdbc12a.bdf12

更新:我更新了我的答案,稍微更改了 sed,现在它可以处理 http/https/www 并将返回介于 https/https/www.com 之间的内容。而且还是比较短的网游。

【讨论】:

  • 我还小??我在哪里。无论如何@BigOldTree 你一个班轮几乎工作,但我不希望问题是这些域名提出任何可变的 RFC 格式,例如 msn.com 或 www.msn.com 或进一步 abc.xyz.com?在那里我认为与已知域名匹配更好。
  • 小家伙是我写的 sed :) 是的,你可以将第二组更改为你需要的,我想你明白了。
  • @BigOldTree 谢谢我的帮助
【解决方案2】:

您提到sed 解决方案是最受欢迎的,但我相信awk 将最容易用于您的特定任务。这是我的解决方案:

awk '/^[[:digit:]]\.[[:digit:]]\.[[:digit:]]\.[[:digit:]]/ { printf $1; gsub (/http\:\/\//," "); gsub(/\.com/," ");printf " "$4"\n"  }' inputFile.txt

这个想法很简单:默认情况下awk 的字段分隔符是空格并允许打印特定字段,因此首先我们匹配以 ip 地址开头的行(四个数字点交替模式);我们打印第一个字段,然后去掉https.com 部分,只剩下域名,因此变成了第4个字段,我们接下来打印。其余部分未指定打印,因此被忽略。

如果您想要编辑原始文件,awk 有一个怪癖,即它无法进行内联编辑,除非那是 gawk (GNU awk),因此为此目的使用临时文件。

演示:

我的输入文件

xieerqi:$ cat inputFile.txt                                               
bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
1.1.1.1 Intel::DOMAIN   from http://abcd.com/bl/BOOT via intel.criticalstack.com     F

whatever.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
2.2.2.2 Intel::DOMAIN   from http://asdf.com/bl/BOOT via intel.criticalstack.com     F

带有临时文件传输的命令(注意我的 inputFile.txt 在我的主目录中,相应地调整该部分)。注意:始终始终备份原始文件以防万一!或者在&&之前运行命令的第一部分,检查临时文件,如果你喜欢,将文件cat到原始文件中。

awk '/^[[:digit:]]\.[[:digit:]]\.[[:digit:]]\.[[:digit:]]/ { printf $1; gsub (/http\:\/\//," "); gsub(/\.com/," ");printf " "$4"\n"  }' inputFile.txt > /tmp/temp.txt && cat /tmp/temp.txt > $HOME/inputFile.txt

命令运行后的输出:

xieerqi:$ awk '/^[[:digit:]]\.[[:digit:]]\.[[:digit:]]\.[[:digit:]]/ { printf $1; gsub (/http\:\/\//," "); gsub(/\.com/," ");printf " "$4"\n"  }' inputFile.txt > /tmp/temp.txt && cat /tmp/temp.txt > $HOME/inputFile.txt


xieerqi:$ cat inputFile.txt                                                                                                                           
1.1.1.1 abcd
2.2.2.2 asdf

通过脚本简化

上面的命令可以放在一个脚本中,内容如下:

#!/usr/bin/awk -f

/^[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*/ { 
printf $1; 

gsub (/http\:\/\//," "); 
gsub (/https\:\/\//," "); 
gsub(/\.com/," ");
printf " "$4"\n";
}

请注意,在脚本中,我考虑了 IP 地址中存在多个数字的可能性以及地址中 https 的可能性。

记得使用chmod 755 /path/to/script使脚本可执行

这是演示:

xieerqi:$ chmod 755 ipanddomain.awk                                                                                                                   

xieerqi:$ cat inputFile.txt                                                                                                                           
bigspeedpro.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
1.1.1.1 Intel::DOMAIN   from http://abcd.com/bl/BOOT via intel.criticalstack.com     F

whatever.com Intel::DOMAIN   from http://malc0de.com/bl/BOOT via intel.criticalstack.com     F
192.168.0.2 Intel::DOMAIN   from https://asdf.foobar.whatever.com/bl/BOOT via intel.criticalstack.com     F

xieerqi:$ ./ipanddomain.awk inputFile.txt                                                                                                             
1.1.1.1 abcd
192.168.0.2 asdf.foobar.whatever

要编辑原始文件,请使用重定向到临时文件并返回原始文件的技巧,就像我之前向您展示的那样

编辑#2

所以您问:是否可以简单地匹配您已经知道的域名的一部分才被打印出来。我已经稍微编辑了我的脚本。基本上,这个版本在 $4 字段中查找模式,如果找到,它会显示“好的,那个字符串里面有 abcd,所以我就打印那个”

#!/usr/bin/gawk -f

/^[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*/ { 
printf $1" ";
matchDomain($4);
}

function matchDomain(str){

if (str~/foobar/)
 printf "foobar\n";
if(str~/abcd/)
 printf "abcd\n"

}

【讨论】:

  • 只要http:.com 之间没有空格(考虑到它是一个网址,应该没有),整个域仍将被视为4美元,换句话说,应该没有任何问题。让我编辑我的答案以包含它,很快就会回来
  • IP地址都是一个数字吗?或者有没有192.168.0.25这样的地址?
  • 好的,我改进了我的答案,简化了一点,并考虑了多位数的 IP 地址以及https 的可能性。
  • 太棒了,乐于助人!因此,如果我的回答解决了您的问题,请通过单击向上/向下箭头旁边的灰色复选标记将其标记为已接受。谢谢!
  • 是的,它给出了很长的输出,因为它只切断了 .com 部分。我们还需要添加 gsub 命令来剪切 .net 部分。并且可以搜索和替换已知字符串。请提供一个例子
猜你喜欢
  • 2011-12-27
  • 1970-01-01
  • 2018-03-28
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 2017-05-23
  • 2019-04-10
相关资源
最近更新 更多