Bash: So holen Sie einige Zeilen aus einer Datei und speichern die Ausgabe in einer anderen Datei [geschlossen]

Jan 17 2021

Ich habe eine Protokolldatei wie diese

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

So generieren Sie wie neu analysierte Protokolle, sodass die Ausgabe des neuen Dateiprotokolls folgendermaßen aussieht:

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

Als ob Sie nur den letzten Fortschritt [ 60% 60920/101076]bis zum Ende der Datei erhalten, indem Sie vielleicht grep, sed oder irgendetwas verwenden. Vielen Dank

Antworten

dawg Jan 17 2021 at 22:29

Hier ist ein Perl:

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

Oder eine Perlpfeife:

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

Für eine können awkSie tun:

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

Natürlich können Sie wissen, dass, wenn der Fehler immer 3 Zeilen beträgt, die einfachste nur verwendet wird tail:

$ tail -n 3 file

Alle drucken:

[ 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

awkist das richtige Werkzeug für solche Dinge. Hier prüfen wir, ob das 2. Feld mit dem 2. Feld der vorherigen Zeile übereinstimmt, und drucken, wenn dies der Fall ist. Speichern Sie dann die vorherige Zeile und wiederholen Sie den Vorgang. Drucken Sie immer die letzte Zeile der Eingabe.

potong Jan 17 2021 at 18:07

Dies könnte für Sie funktionieren (GNU sed):

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

Wenn eine Zeile beginnt, [speichern Sie sie im Haltebereich (überschreiben Sie alles, was zuvor dort vorhanden war).

Andernfalls hängen Sie die aktuelle Zeile an den Haltebereich an.

Löschen Sie alle Zeilen außer der letzten.

Wechseln Sie am Ende der Datei in den Haltebereich und drucken Sie den Inhalt.

IdrissNeumann Jan 17 2021 at 18:15

Sie haben manchmal kein Glück, wenn Sie diese Art von Filter ausführen möchten, ohne die Reihenfolge der Zeilen ändern zu müssen. Und wenn diese Zeilen nicht am Anfang der Datei, oder am Ende geschrieben: tac, sortund uniqwürden nicht die richtigen Werkzeuge sein.

Hier ist eine Lösung mit 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)) ####

Die lesbare und erklärte Version:

# 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]
    }
  }
}

Der Unterschied zu den William Pursel-Lösungen besteht darin, dass Ihre Prozentsätze steigen. Lassen Sie uns den Unterschied im Verhalten in diesem Fall sehen:

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

Sie können also wählen, ob Sie nur die letzte Fortschrittslinie beibehalten möchten, auch wenn der Prozentsatz nicht gleich ist, oder ob Sie nur die Linien filtern möchten, die denselben Prozentsatz mehrmals haben.

Enlico Jan 17 2021 at 18:47

Wenn garantiert ist, dass die erste Zeile, die Sie ausgeben möchten, die letzte Zeile ist, mit der begonnen wird [, können Sie dies tun, wobei im Wesentlichen alles vom Anfang der Datei bis zur letzten Zeile , der [ein Zeilenumbruch vorausgeht, durch eine einzelne ersetzt wird [:

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

Angenommen, die ...Zeile am Anfang Ihrer Beispieleingabe repräsentiert mehr führende [...] ...Zeilen:

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

Wenn diese Annahme falsch ist, bearbeiten Sie bitte Ihre Frage, um ein minimales, vollständiges und überprüfbares Beispiel anzuzeigen - eines mit nur repräsentativen Werten, nicht ...s.