Siduction Forum > Scripting & Kernelhacking

[DE] Zeilen zusammenfassen

(1/1)

bluelupo:
Hallo zusammen,

ich würde gerne folgende extrahierte Zeilen aus /var/log/apt/history.log jeweils in einer zusammenfassen:

So siehst es aus:

--- Code: ---Start-Date: 2015-01-12  17:11:15
Commandline: apt-get dist-upgrade
Start-Date: 2015-01-14  16:58:30
Commandline: apt-get dist-upgrade

--- End code ---

Soll dann so aussehen:

--- Code: ---Start-Date: 2015-01-12  17:11:15 Commandline: apt-get dist-upgrade
Start-Date: 2015-01-14  16:58:30 Commandline: apt-get dist-upgrade

--- End code ---

Wie kann ich das in einem Shellscript-Einzeiler erledigen?

bluelupo:
Hab's gelöst und gebe mir selbst die Antwort ;-)


--- Code: ---egrep '(Start-Date:.*|Commandline: apt-get )' /var/log/apt/history.log | sed '$!N;s/\n/ /'

--- End code ---

Der sed-Befehl fügt immer paarweise die Zeilen zusammen. Die Lösung kam von dieser Seite unter "Füge Zeilenpaare nebeneinander zusammen".

Okay, jetzt habe ich die Lösung, aber verstehen tue ich den sed-Ausdruck nicht :-( Nur soviel das irgendwas durch ein Leerzeichen ersetzt wird. Vielleicht gibt es hier Spezialisten die das auflösen können.

hefee:
also "s/\n/ /" ist die normale ersetzung von  newlines durch leerzeichen, denn \n ist ein newline Zeichen und das wird durch ein Leerzeichen ersetzt. Jetzt ist aber leider sed so gestrickt, dass es nur zeilenweise arbeitet, also müssen wir dafür sorgen das immer zwei Zeilen zusammen in den Puffer kommen, dann ereichen wir mit N;

Sauberer wäre es wenn du so was schreibst: N; s/\nCommandline/ Commandline/, dann stellst du sicher, das wirklich die richtigen Zeile zusammengefasst werden.

bluelupo:
Danke für die Erklärung hefee  :) :)

musca:
Hallo,

guter Hinweis von hefee, das blinde paarweise Zusammenfügen reicht vermutlich nicht. Denn ich habe in meinem history.log auch Einträge dieser Art (also ohne die folgende "Commandline"):
Start-Date: 2015-01-22  18:11:10
End-Date: 2015-01-22  18:11:11

Start-Date: 2015-01-22  18:11:33
End-Date: 2015-01-22  18:11:33

Ich vermute, dass ich hier den Solver von Aptitude bei der Sicherheitsabfrage "Wollen Sie wirklich?" abgebrochen habe.
Dadurch kann also die paarweise Verkettung aus dem Takt kommen.


Mit perl könnte eine Lösung so aussehen ( Newline nur vor dem Wort Commandline durch Space ersetzen)

--- Code: ---perl -0ne 's/\RCommandline/ Commandline/g; print;' /var/log/apt/history.log | grep Commandline

--- End code ---


Nach einer kleinen Optimierung entfällt sowohl das Multiline-Reading (-0) als auch noch das anschliessende grep:

--- Code: ---perl -ne 'chomp;print$l=(/^Com/)?"$l$_\n":"";$l="$_ "' /var/log/apt/history.log
--- End code ---
Durch die Optionen -n wird dabei implizit folgendes ausgeführt:
#!/usr/bin/perl
# concatenate all lines beginning with "Commandline" with the previous line
 use strict;
 use warnings;  # -w switch

{
  while (<>) {               # The -n switch reads filename arguments or STDIN
    chomp;                   # remove trailing newline
    if (/^Commandline/) {    # actual record does begin with "Commandline"
      print "$last$_\n"      # append previous record with actual record
    } else {                 # not yet found a Commandline!
      print ""               # so print nothing in this case (avoid grep)
    }
    $last = "$_ "            # remember actual record until next loop
  }
}


Okay, den else-Teil läßt man nun weg.
Schließlich kann man die -l Option verwenden, um chomp und print zu vereinfachen.

--- Code: ---perl -wlne 'print "$last $_" if (/^Command/); $last=$_' /var/log/apt/history.log
oder
perl -wlne '/^Command/ && print "$last $_"; $last=$_' /var/log/apt/history.log
--- End code ---

Die Syntax ist auf einmal wieder recht ähnlich zu awk:

--- Code: ---awk '/^Command/ { print last " " $0;} { last=$0; }' /var/log/apt/history.log
--- End code ---

oder sed:

--- Code: ---sed '/^Com/!{h;d};/^Com/{x;G;s/\n/  /}' </var/log/apt/history.log
--- End code ---

[edit: hier noch ein Oneliner in bash:]

--- Code: ---while read line; do [[ $line =~ Commandline ]] && printf "%s  %s\n" "$last" "$line"; last="$line"; done < /var/log/apt/history.log
--- End code ---


perlish greetings
musca

Navigation

[0] Message Index

Go to full version
Powered by Advanced Topic Prefix Pro
Powered by SMFPacks WYSIWYG Editor