Bash: Cómo obtener algunas líneas de un archivo y guardar la salida en otro archivo [cerrado]

Jan 17 2021

Tengo un archivo de registro como este

$ cat build.log
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Cómo generar como nuevos registros analizados para que la salida del nuevo registro de archivos sea así:

$ cat parsed.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Como solo obtener el último progreso [ 60% 60920/101076]hasta el final del archivo, usando tal vez grep, sed o cualquier cosa. Gracias

Respuestas

dawg Jan 17 2021 at 22:29

Aquí hay una perl:

$ perl -0777 -lne 'print $1 if /(^\[[^[]*\z)/m' file

O una pipa de perl:

$ perl -E 'say reverse <>' file | perl -lpE 'if (/^\[/){ say; last}' | perl -E 'say reverse <>'

Por un awkpuedes hacer:

$ awk 'BEGIN{RS="\\["}END{print "[" $0}' file

Por supuesto, puede saber que si la falla es siempre de 3 líneas, la más simple es usar tail:

$ tail -n 3 file

Todo impreso:

[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
WilliamPursell Jan 17 2021 at 17:57
$ cat build.log ........ [ 60% 60917/101076] AAPT2 compile .... [ 60% 60918/101076] AAPT2 compile .... [ 60% 60919/101076] AAPT2 compile .... [ 60% 60920/101076] AAPT2 compile .... ninja: build stopped: subcommand failed. 21:41:22 ninja failed with: exit status 1 $ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' build.log
........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

awkes la herramienta adecuada para este tipo de cosas. Aquí, verificamos si el segundo campo coincide con el segundo campo de la línea anterior e imprimimos si lo hace. Luego guarde la línea anterior y repita. Imprima siempre la última línea de la entrada.

potong Jan 17 2021 at 18:07

Esto podría funcionar para usted (GNU sed):

sed '/^\[/h;//!H;$!d;x' file

Si comienza una línea, [guárdela en el espacio de espera (sobrescribiendo cualquier cosa que estuviera allí).

De lo contrario, agregue la línea actual al espacio de espera.

Elimina todas las líneas excepto la última.

Al final del archivo, cambie al espacio de espera e imprima su contenido.

IdrissNeumann Jan 17 2021 at 18:15

A veces no tienes suerte si quieres realizar este tipo de filtro sin tener que cambiar el orden de las líneas. Y si esas líneas no están escritos en el principio del archivo, o al final: tac, sorty uniqno serían las herramientas adecuadas.

Aquí hay una solución usando awk:

$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log 
..........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

La versión legible y explicada:

# a function to append an element to an array dynamically
function push(a,e) { 
  a[length(a)+1] = e 
} 

BEGIN {
  split("", lines); # initializing an array
  to_replace="toreplace"; # you can change the replace key if you want
  exists=0
} 

{
  if ($0 ~ "^\\[ [0-9]+%"){ # matching all percentages/progression lines, regardless of their values ll=$0; 
    if (exists <= 0) {
      exists++; 
      push(lines, to_replace)
    }
  } else {
    push(lines, $0)
  }
}

END {
  for (e in lines) {
    if (lines[e] == to_replace) {
      print ll
    } else {
      print lines[e]
    }
  }
}

La diferencia con las soluciones de William Pursel es cuando sus porcentajes aumentan. Veamos la diferencia de comportamiento en este caso:

$ cat test.log 
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####
$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log 
..........
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####
$ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' test.log 
..........
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Por lo tanto, es posible que desee elegir si solo desea mantener la última línea de progresión incluso si el porcentaje no es el mismo o si solo desea filtrar las líneas que tienen el mismo porcentaje varias veces.

Enlico Jan 17 2021 at 18:47

Si está garantizado que la primera línea con la que desea salir es la última línea que comienza con [, entonces puede hacer esto, que esencialmente reemplaza todo desde el principio del archivo hasta la última [precedida por un salto de línea con un solo [:

sed -z 's/.*\n\[/[/' file
EdMorton Jan 17 2021 at 22:50

Suponiendo que la ...línea al comienzo de la entrada de muestra representa más [...] ...líneas principales :

$ awk '/^\[/{p=$0 ORS; next} {print p $0; p=""}' build.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Si esa suposición es incorrecta, edite su pregunta para mostrar un ejemplo mínimo, completo y verificable, uno con solo valores representativos, no ...s.