
Quero pegar algumas partes do meu arquivo de log, tentei cortar a parte da solicitação para pegar o usuário, módulo, ação, doAjax e ajaxAction
Por exemplo, eu tenho
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
e eu quero ter:
[user]|[module]|[action]|[doAjax]|[ajaxAction]
usery contacts form null null
userx customer null request getContacts
userz meeting null date null
Onde:
userx --> user
m=xxx -->module
a=xxx -->action
doajax=xxx-->doAjax
action=xxx-->ajaxAction
Tentei usar awk
, set mas for para cortar apenas a 7ª coluna onde posso encontrar minha requisição com este comando:
awk '{printf $7; next ; }' logfile
Então, como posso extrair o usuário, módulo, ação, doAjax e ajaxAction depois de imprimir apenas minha solicitação?
Responder1
Uma "linha única" 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
O truque básico aqui é procurar cada uma das strings que identificam as partes do seu URL e, se encontradas, definir a variável correspondente para elas. Em cada caso, procuramos o identificador seguido por um =
(por exemplo m=
) e depois por um &
ou pelo final da linha (&|$)
. Como a parte correspondente é colocada entre parênteses (por exemplo, m=(.+?)
), podemos então nos referir a ela como $2
e é isso que é salvo em cada variável.
Se você realmente precisa ter |
um separador e não se opõe ao fato de que isso tornará a saída menos legível, você pode usar isto:
$ 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
Uma abordagem melhor (saída mais legível) seria usar printf
:
Responder2
Se preferir fazer isso no awk, você pode fazer o seguinte. Split permite dividir uma string com qualquer separador de campo.
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
Isso gera as colunas desejadas.
userx contacts a form
usery customer doajax request
userx meeting doajax date
A etapa restante é formatar. Arrays no awk são associativos e podem ser indexados com strings - vejaaqui. Você pode fazer o seguinte; aqui, op (abreviação de saída) é inicializado como nulo. Então, definimos 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
[modificado para]
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
A saída é a seguinte
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
Responder3
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
Resultados
[user]|[module]|[action]|[doAjax]|[ajaxAction]
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
Explicação
Opções Perl:
-l
fazORS = RS = \n
-a
armazena campos em uma matriz@F
obtida pela divisão do registro atual em/\s+/
, por exemplo,$F[0] => $1, $F[1] => $2, ..., $F[-1] => $NF
-n
configura um loop implícito que lê o arquivo de entrada linha por linha E nenhuma saída, a menos que solicitado.Bloco BEGIN:
Primeiro imprimimos o cabeçalho. Em seguida, determinamos o formato dinamicamente com base no cabeçalho. Para cada linha lida, configuramos um hash %h cujas chaves são as strings antes de = e os valores são as strings depois de =. A string a ser observada é delimitada por ? ou & à esquerda e & à direita. A seguir, configuramos outro hash %H cujas chaves são versões renomeadas do hash %h. Em seguida, imprimimos o hash com base no formato que calculamos no bloco BEGIN.