我想从日志文件中获取一些部分,我尝试剪切请求部分以获取用户、模块、操作、doAjax 和 ajaxAction
例如,我有
195.xx.x.x - - [25/Apr/2017:09:60:xx +0200] "POST /userx/index.php?m=contacts&a=form&...
192.xx.x.x - - [25/Apr/2017:09:45:xx +0200] "POST /usery/index.php?m=customer&doajax=request&action=getContacts...
197.xx.x.x - - [25/Apr/2017:09:20:xx +0200] "GET /userx/index.php?m=meeting&doajax=date&id=3
我想要:
[user]|[module]|[action]|[doAjax]|[ajaxAction]
usery contacts form null null
userx customer null request getContacts
userz meeting null date null
在哪里:
userx --> user
m=xxx -->module
a=xxx -->action
doajax=xxx-->doAjax
action=xxx-->ajaxAction
我尝试使用awk
, set but for 只剪切第七列,我可以在其中使用以下命令找到我的请求:
awk '{printf $7; next ; }' logfile
那么,在打印我的请求后,我该如何提取用户、模块、操作、doAjax 和 ajaxAction 呢?
答案1
Perl“一行”:
$ perl -lne '
BEGIN{
printf "%-10s%-10s%-10s%-10s%-15s\n", qw([user] [module] [action] [doAjax] [ajaxAction]);
}
$usr = $mde = $act = $doAj = $ajAc = "null";
$usr=$1 if m|\s/([^/]+)/|;
$mde=$1 if /m=(.+?)(&|$)/;
$act=$1 if /a=(.+?)(&|$)/;
$doAj=$1 if /doajax=(.+?)(&|$)/;
$ajAc=$1 if /action=(.+?)(&|$)/;
printf "%-10s%-10s%-10s%-10s%-15s\n", ($usr,$mde,$act,$doAj,$ajAc)' file
[user] [module] [action] [doAjax] [ajaxAction]
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
这里的基本技巧是搜索标识 URL 部分的每个字符串,如果找到,则为其设置相应的变量。在每种情况下,我们都会查找标识符,后跟一个=
(例如m=
),然后是一个&
或行尾(&|$)
。因为匹配的部分放在括号中(例如m=(.+?)
),所以我们可以将其称为 ,$2
这就是每个变量中保存的内容。
如果您确实需要|
作为分隔符,并且不反对它会使输出的可读性较差,您可以使用它:
$ perl -lne '
BEGIN{
printf "%s|%s|%s|%s|%s\n", qw([user] [module] [action] [doAjax] [ajaxAction]);
}
$usr = $mde = $act = $doAj = $ajAc = "null";
$usr=$1 if m|\s/([^/]+)/|;
$mde=$1 if /m=(.+?)(&|$)/;
$act=$1 if /a=(.+?)(&|$)/;
$doAj=$1 if /doajax=(.+?)(&|$)/;
$ajAc=$1 if /action=(.+?)(&|$)/;
print join "|", ($usr,$mde,$act,$doAj,$ajAc)' file
[user]|[module]|[action]|[doAjax]|[ajaxAction]
userx|contacts|form|null|null
usery|customer|null|request|getContacts
userx|meeting|null|date|null
更好的(更易读的输出)方法是使用printf
:
答案2
如果您喜欢在 awk 中执行此操作,可以执行以下操作。拆分允许您使用任何字段分隔符拆分字符串。
awk '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); print a[2], c[1], d[1], d[2] }' logfile
这会生成所需的列。
userx contacts a form
usery customer doajax request
userx meeting doajax date
剩下的步骤是格式化。 awk 中的数组是关联的,并且可以用字符串索引 - 请参阅这里。您可以执行以下操作;此处,op(输出的缩写)被初始化为 null。然后,我们设置op[d[1]]=d[2]
.
awk '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); op["a"]="null"; op["doajax"]="null"; op["ajaxaction"]="null"; op[d[1]]=d[2];print a[2], c[1], op["a"], op["doajax"], op["ajaxaction"] }' junk.txt
[修改为]
awk '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); op["a"]="null"; op["doajax"]="null"; op["action"]="null"; op[d[1]]=d[2]; split(c[3],f,"="); split(f[2],g,"."); op[f[1]]=g[1]; print a[2], c[1], op["a"], op["doajax"], op["action"] }' junk.txt
输出如下
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
答案3
perl -lane '
BEGIN {
print $H = join "|", map { s/.*/[$&]/r } @H = qw/user module action doAjax ajaxAction/;
pos($H) = 0;
push(@pos, pos($H)-$p), $p=pos($H) while $H =~ /\[/g;
$fmt = join "", map { "\%-${_}s" } @pos[1..$#pos], length($H)-$p;
}
my(%h, %H) = $F[-1] =~ /[?&]\K([^=]+)=([^&]+)/g;
@H{@H} = ($F[-1] =~ m|^/([^/]+)|, @h{qw/m a doajax action/});
print sprintf $fmt, map { $H{$_} // "null" } @H;
' logfile
结果
[user]|[module]|[action]|[doAjax]|[ajaxAction]
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
解释
Perl 选项:
-l
使ORS = RS = \n
-a
将字段存储在@F
通过拆分当前记录获得的数组中/\s+/
,因此例如,$F[0] => $1, $F[1] => $2, ..., $F[-1] => $NF
-n
设置一个隐式循环,逐行读取输入文件,除非要求,否则不输出。开始块:
首先我们打印标题。然后我们根据 header 动态确定格式。对于读取的每一行,我们设置一个哈希 %h,其键是=之前的字符串,值是=之后的字符串。要查看的字符串紧邻 ?或 & 位于左侧,& 位于右侧。接下来,我们设置另一个哈希 %H,其键被重命名为 %h 哈希的版本。接下来,我们根据 BEGIN 块中计算的格式打印哈希值。