
Quiero obtener algunas partes de mi archivo de registro. Intenté cortar la parte de la solicitud para obtener el usuario, el módulo, la acción, doAjax y ajaxAction.
Por ejemplo, tengo
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
y quiero tener:
[user]|[module]|[action]|[doAjax]|[ajaxAction]
usery contacts form null null
userx customer null request getContacts
userz meeting null date null
Dónde:
userx --> user
m=xxx -->module
a=xxx -->action
doajax=xxx-->doAjax
action=xxx-->ajaxAction
Intenté usar awk
, pero para cortar solo la séptima columna donde puedo encontrar mi solicitud con este comando:
awk '{printf $7; next ; }' logfile
Entonces, ¿cómo puedo extraer el usuario, el módulo, la acción, doAjax y ajaxAction después de imprimir solo mi solicitud?
Respuesta1
Una "de una sola línea" de 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
El truco básico aquí es buscar cada una de las cadenas que identifican las partes de su URL y, si las encuentra, establecer la variable correspondiente. En cada caso, buscamos el identificador seguido de =
(p. ej. m=
) y luego a &
o el final de la línea (&|$)
. Debido a que la parte coincidente se coloca entre paréntesis (por ejemplo m=(.+?)
), podemos referirnos a ella como $2
y eso es lo que se guarda en cada variable.
Si realmente necesita tenerlo |
como separador y no se opone al hecho de que hará que la salida sea menos legible, puede usar esto en su lugar:
$ 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
Un enfoque mejor (salida más legible) sería utilizar printf
en su lugar:
Respuesta2
Si prefieres hacer esto en awk, puedes hacer lo siguiente. Dividir le permite dividir una cadena con cualquier 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
Esto genera las columnas deseadas.
userx contacts a form
usery customer doajax request
userx meeting doajax date
El paso restante es formatear. Las matrices en awk son asociativas y se pueden indexar con cadenas; consulteaquí. Puedes hacer lo siguiente; aquí, op (abreviatura de salida) se inicializa en nulo. Luego, fijamos 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 a]
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
La salida es la siguiente
userx contacts form null null
usery customer null request getContacts
userx meeting null date null
Respuesta3
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
Explicación
Opciones de Perl:
-l
marcasORS = RS = \n
-a
almacena los campos en una matriz@F
obtenida al dividir el registro actual/\s+/
, por lo que, por ejemplo,$F[0] => $1, $F[1] => $2, ..., $F[-1] => $NF
-n
configura un bucle implícito que lee el archivo de entrada línea por línea Y no genera salida a menos que se solicite.Bloque COMENZAR:
Primero imprimimos el encabezado. Luego determinamos el formato dinámicamente según el encabezado. Para cada línea leída, configuramos un hash %h cuyas claves son las cadenas antes de = y los valores son la cadena después de =. La cuerda que se va a mirar está colindante con ? o & a la izquierda y & a la derecha. A continuación, configuramos otro hash %H cuyas claves son versiones renombradas del hash %h. A continuación imprimimos el hash según el formato que calculamos en el bloque BEGIN.