Welcome, Guest. Please login or register.
Did you miss your activation email?

Author Topic: [DE] Zeilen zusammenfassen  (Read 8250 times)

Offline bluelupo

  • User
  • Posts: 2.068
    • BluelupoMe
[DE] Zeilen zusammenfassen
« on: 2015/01/22, 19:23:19 »
Hallo zusammen,

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

So siehst es aus:
Code: [Select]
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

Soll dann so aussehen:
Code: [Select]
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

Wie kann ich das in einem Shellscript-Einzeiler erledigen?

Offline bluelupo

  • User
  • Posts: 2.068
    • BluelupoMe
Re: Zeilen zusammenfassen
« Reply #1 on: 2015/01/22, 20:27:26 »
Hab's gelöst und gebe mir selbst die Antwort ;-)

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

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.
« Last Edit: 2015/01/22, 21:41:50 by bluelupo »

hefee

  • Guest
Re: Zeilen zusammenfassen
« Reply #2 on: 2015/01/22, 21:04:44 »
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.

Offline bluelupo

  • User
  • Posts: 2.068
    • BluelupoMe
Re: Zeilen zusammenfassen
« Reply #3 on: 2015/01/22, 21:09:43 »
Danke für die Erklärung hefee  :) :)

Offline musca

  • User
  • Posts: 725
  • sid, fly high!
Re: Zeilen zusammenfassen
« Reply #4 on: 2015/01/23, 23:56:10 »
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: [Select]
perl -0ne 's/\RCommandline/ Commandline/g; print;' /var/log/apt/history.log | grep Commandline


Nach einer kleinen Optimierung entfällt sowohl das Multiline-Reading (-0) als auch noch das anschliessende grep:
Code: [Select]
perl -ne 'chomp;print$l=(/^Com/)?"$l$_\n":"";$l="$_ "' /var/log/apt/history.logDurch 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: [Select]
perl -wlne 'print "$last $_" if (/^Command/); $last=$_' /var/log/apt/history.log
oder
perl -wlne '/^Command/ && print "$last $_"; $last=$_' /var/log/apt/history.log

Die Syntax ist auf einmal wieder recht ähnlich zu awk:
Code: [Select]
awk '/^Command/ { print last " " $0;} { last=$0; }' /var/log/apt/history.log
oder sed:
Code: [Select]
sed '/^Com/!{h;d};/^Com/{x;G;s/\n/  /}' </var/log/apt/history.log
[edit: hier noch ein Oneliner in bash:]
Code: [Select]
while read line; do [[ $line =~ Commandline ]] && printf "%s  %s\n" "$last" "$line"; last="$line"; done < /var/log/apt/history.log

perlish greetings
musca
« Last Edit: 2015/12/03, 19:59:59 by musca »
„Es irrt der Mensch, solang er strebt.“  (Goethe, Faust)