PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Messdaten extrahieren/zeilenweise kopieren mit sed(?)



jori
11-05-2009, 05:19
Hallo,

Ich habe den Wunsch aus mehreren Messdaten (*.dat)

-die ersten 8 Zeilen, (sed-Magie1)

-Zeile 100 (sed-Magie2)

-Zeile 250 (sed-Magie3)

-und die Zeile in der MUSTER (; 2.00) zum ersten Mal vorkommt (sed-Magie4)

in eine Datei zu schreiben die vor dem alten Dateinamen noch ein edit (o.ä.) stehen hat


Ich bin noch "blutiger" Anfänger im Skripteschreiben, trotzdem der Versuch es darzustellen:


#!/bin/bash

DAT="*.dat" #charateristische Endung der Messdateien

for f in $DAT
do

cat $f | sed -e "sed-Magie1" <$f >tmp.$$
-e "sed-Magie2" <$f >>tmp$$ #um Ausgabe von Befehl2 an tmp.$$ anzuhängen(?)
-e "sed-Magie3" <$f >>tmp$$
-e "sed-Magie4" <$f >>tmp$$
mv tmp.$$ edit$f
done


Mir fehlen aber noch die entscheidenden Formeln das ganze zu verwirklichen.
ich danke euch im Vorraus

Johannes

jan61
11-05-2009, 19:18
Moin,

zuerst ein paar Bemerkungen zu Deinem Script:



#!/bin/bash

DAT="*.dat" #charateristische Endung der Messdateien

for f in $DAT
do

cat $f | sed -e "sed-Magie1" <$f >tmp.$$
-e "sed-Magie2" <$f >>tmp$$ #um Ausgabe von Befehl2 an tmp.$$ anzuhängen(?)
-e "sed-Magie3" <$f >>tmp$$
-e "sed-Magie4" <$f >>tmp$$
mv tmp.$$ edit$f
done


- cat ist überflüssig, Du kannst sed den Dateinamen direkt als Argument übergeben.
- <$f ist doppelt gemoppelt, damit fütterst Du sed aus der Pipe und aus STDIN
- Die Ein- und Ausgabeumleitung zwischen den einzelnen -e-Optionen wird nicht funktionieren, das hängt man hinter die letzte Option bzw. das letzte Argument.
- Mehrere sed-Kommandos kann man mit Semikolon trennen, das ist übersichtlicher als viele -e-Optionen

So, und nun zum Thema: Ich habe mir erstmal Beispieldaten gebastelt:

jan@jack:~/tmp> for i in `seq 1 1000`; do echo -n "line $i" >>daten; test $i -eq 123 -o $i -eq 555 && echo -n " ;2.00 blablubb" >>daten; echo >>daten; done
jan@jack:~/tmp> sed 's/^/data2 /' daten >data2
So, und jetzt die Schleife + sed:

jan@jack:~/tmp> for dat in dat*; do
> sed -rn '1,8p;100p;250p;/;2\.00/H;${g;s/\n(.+)\n.*/\1/;p}' $dat >>edit.txt
> done
jan@jack:~/tmp> cat edit.txt
data2 line 1
data2 line 2
data2 line 3
data2 line 4
data2 line 5
data2 line 6
data2 line 7
data2 line 8
data2 line 100
data2 line 250
data2 line 123 ;2.00 blablubb
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
line 100
line 250
line 123 ;2.00 blablubb
Ist nur oberflächlich getestet.

Jan

EDIT: Mit ist noch eine Möglichkeit eingefallen, wie man die erste Zeile, die ";2.00" matcht, in der richtigen Reihenfolge ausgibt (das vorige Beispiel hat sie ja angehängt):

sed -rn '1,8p;100p;250p;/;2\.00/{x;/^$/{x;p};h}' datenDas sollte ich vielleicht doch mal kurz kommentieren ;-)

Die ersten 3 Anweisungen ("1,8p;100p;250p;") sind wohl klar. Die nächste geschachtelte Anweisung ist die knifflige:

"/;2\.00/{...}" - Wenn die Zeile matcht, dann führe den Codeblock in den äußeren {} aus

"x;/^$/{x;p}" - tausche Inhalt von hold und pattern space aus (der Pattern space beinhaltet den Match, also hier die betreffende Zeile). Wenn jetzt der Pattern Space leer ist (beim ersten Treffer), dann tausche wieder Pattern und Hold Space (jetzt haben wir im Pattern Space wieder unsere Zeile) und gib sie aus.

"h" - Kopiere den Inhalt des Pattern Space (unsere Zeile) in den Hold Space; damit steht nach dem ersten Treffer im Hold Space diese Zeile und ist bei den nächsten Anfrage nicht mehr leer - voila!

Komisch - ich hatte doch noch was angehängt; wohl vergessen zu speichern - naja: Wenn eine Zeile, auf die das Pattern matcht, zufälligerweise eine der in den Zeilennummern aufgeführten ist, dann wird sie 2x ausgegeben. Das verhindert man, indem man die Reihenfolge der Anweisungen vertauscht (erst das PAttern, dann der Rest) und für das Pattern noch ein "d" (lösche den Pattern Space und mache mit der nächsten Zeile weiter) einfügt:

sed -rn '/;2\.00/{x;/^$/{x;p};h;d};1,8p;100p;250p' datenEs lässt mich nicht los ;-) die letzte Version behandelt die Regel "nur die erste auf ;2.00 matchende Zeile ausgeben" mit höherer Priorität als die Regel "Zeilen 1..8, 100, 250 ausgeben". Wenn also eine 2. Zeile innerhalb der gewünschten Zeilennummern auch das Pattern enthält, dann wird sie nicht ausgegeben.

Wenn man es andersrum haben will, dann modifiziert man so:

sed -rn '/;2\.00/{x;/^$/{x;p;h;d};x;h};1,8p;100p;250p' datenOb das überhaupt auftreten kann, weiss ich nicht - vielleicht sind die Zeilen, die per Zeilennummer ausgegeben werden, ja irgendwelche Header oder Überschriften - eben nur für alle Fälle.

Nimmt das denn gar kein Ende? ;-) Es gibt ja noch eine Variante (da sieht man mal, was mangelnde Spezifikation ausrichtet): Gesetzt den Fall, dass die Zeilennummern höhere Priorität haben und eventuelle Matches gegen das Pattern bei ihnen überhaupt nicht berücksichtigt werden sollen:

sed -rn '1,8{p;d};100{p;d};250{p;d};/;2\.00/{x;/^$/{x;p};h}' datenSo, jetzt ist aber genug!

jori
13-05-2009, 20:00
@jan:

Danke, Danke!

Es hat geklappt und war lehrreich! Bitte entschuldige die mangelnde Spezifikation.

Gruß

Johannes

jan61
15-05-2009, 20:48
Moin,


Bitte entschuldige die mangelnde Spezifikation.

War nicht bös gemeint - manchmal denkt man als "Insider" schlicht und einfach nicht daran, dass Außenstehende die eine oder andere zusätzliche Info benötigen, um sich eine Vorstellung machen zu können - geht mir auch dann und wann so. Am besten ist immer ein kurzes Beispiel (es müssen ja nicht gleich 250 Zeilen sein ;-)

Jan

P.S.: Welche Variante hat denn gepasst?