Bash: come ottenere alcune righe da un file e salvare l'output in un altro file [chiuso]

Jan 17 2021

Ho un file di registro come questo

$ 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)) ####

Come generare un nuovo registro analizzato in modo che l'output del nuovo registro file sia simile a questo:

$ 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)) ####

Come ottenere solo l'ultimo progresso [ 60% 60920/101076]fino alla fine del file, usando forse grep, sed o altro. Grazie

Risposte

dawg Jan 17 2021 at 22:29

Ecco un perl:

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

O una pipa in perl:

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

Per un awkpuoi fare:

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

Certo, potresti sapere che se l'errore è sempre di 3 righe, il più semplice è solo usare tail:

$ tail -n 3 file

Tutte le stampe:

[ 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

awkè lo strumento giusto per questo genere di cose. Qui, controlliamo se il 2 ° campo corrisponde al 2 ° campo della riga precedente e stampiamo se lo fa. Quindi memorizzare la riga precedente e ripetere. Stampa sempre l'ultima riga dell'input.

potong Jan 17 2021 at 18:07

Questo potrebbe funzionare per te (GNU sed):

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

Se una riga inizia, [memorizzala nello spazio di attesa (sovrascrivendo qualsiasi cosa precedente).

Altrimenti, aggiungi la riga corrente allo spazio di attesa.

Elimina tutte le righe tranne l'ultima.

Alla fine del file, passare allo spazio di attesa e stampare il suo contenuto.

IdrissNeumann Jan 17 2021 at 18:15

A volte non sei fortunato se vuoi eseguire questo tipo di filtro senza dover cambiare l'ordine delle righe. E se quelle linee non sono scritti all'inizio del file, o alla fine: tac, sorte uniqnon sarebbero gli strumenti giusti.

Ecco una soluzione che utilizza 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 versione leggibile e spiegata:

# 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 differenza con le soluzioni William Pursel è quando le tue percentuali aumentano. Vediamo la differenza di comportamento in questo 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)) ####

Quindi potresti scegliere se vuoi solo mantenere l'ultima linea di progressione anche se la percentuale non è la stessa o se vuoi solo filtrare le linee che hanno la stessa percentuale più volte.

Enlico Jan 17 2021 at 18:47

Se è garantito che la prima riga che desideri stampare è l'ultima riga che inizia con [, puoi farlo, che essenzialmente sostituisce tutto dall'inizio del file all'ultimo [preceduto da un'interruzione di riga con un singolo [:

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

Supponendo che la ...riga all'inizio del tuo input di esempio rappresenti più [...] ...linee iniziali :

$ 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)) ####

Se questa ipotesi è sbagliata, modifica la tua domanda per mostrare un esempio minimo, completo e verificabile, uno con solo valori rappresentativi, non ...s.