2010-12-15 6 views
3

Ich habe mit einem bestimmten Dateinamen zu tun, und müssen Informationen aus ihnen extrahieren.eine bestimmte Teilzeichenfolge mit regulären Ausdrücken mit awk

Die Struktur des Dateinamen ist ähnlich: „20100613_M4_28007834.005_F_RANDOMSTR.raw.gz“

mit RandomStr einer Kette von max 22 Zeichen, und der einen Teil (oder nicht) mit dem Format „enthalten - W [0-9]. [0-9] {2}. [0-9] {3} ". Dieser Teilstring hat auch die einzigartige Eigenschaft, mit "-W" zu beginnen.

Die Informationen, die ich extrahieren muss, ist die Teilzeichenfolge von RANDOMSTR ohne diese optionale Teilzeichenfolge.

Ich möchte dies in einem Bash-Skript implementieren, und bis jetzt die beste Option, die ich gefunden habe, ist Gawk mit einem regulären Ausdruck zu verwenden. Mein bester Versuch bisher versagt:

gawk --re-interval '{match ($0,"([0-9]{8})_(M[0-9])_([0-9]{8}\\.[0-9]{3})_(.)_(.*)(-W.*)?.raw.gz",arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz" 
OTHER-STRING-W0.40+045 

Die erwarteten Ergebnisse sind:

gawk --re-interval '{match ($0,$regexp,arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_SOME-STRING.raw.gz" 
SOME-STRING 
gawk --re-interval '{match ($0,$regexp,arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz" 
OTHER-STRING 

Wie kann ich den gewünschten Effekt zu bekommen.

Danke.

+0

Sie haben erwähnt, dass der Teil das Muster hat '" -W [0-9]. [0-9] {2}. [0-9] {3} "' Ihre Beispieleingabe enthält jedoch ... W0.40 + 045.raw.gz'. Müssen Sie beiden gerecht werden? –

+0

Ich schließe die ".raw.gz" nicht als Teil der Teilzeichenfolge ein. – RogerFC

+0

Entschuldigung, ich wollte auf das Pluszeichen aufmerksam machen, das von deinem Muster nicht abgedeckt würde. –

Antwort

2

Sie müssen Look-Arounds verwenden können und ich glaube nicht, dass awk/gawk das unterstützt, aber grep -P tut.

$ pat='(?<=[0-9]{8}_M[0-9]_[0-9]{8}\.[0-9]{3}_._)(.*?)(?=(-W.*)?\.raw\.gz)' 
$ echo "20100613_M4_28007834.005_F_SOME-STRING.raw.gz" | grep -Po "$pat" 
SOME-STRING 
$ echo "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz" | grep -Po "$pat" 
OTHER-STRING 
+0

Das ist definitiv stärker Regex-Fu! +1 –

+1

BTW, funktioniert nicht für mich, es sei denn, ich ändere es in 'pat = '(? <= [0-9] {8} _M [0-9] _ [0-9] {8} \. [0 -9] {3} _._) (. +?) (? = (- W. *)?.. Row \ .gz) ''dh ich musste' (. +?) 'Anstelle von' verwenden (. *?) '. –

+0

@Shawn: '(. +?)' Ist wahrscheinlich besser, aber es funktioniert für mich wie gezeigt. Ich habe einfach die Zeilen aus meiner Antwort kopiert und eingefügt, um sie erneut zu testen, und es funktioniert (egal). –

0

Die Schwierigkeit hier scheint die Tatsache zu sein, dass der (.*) vor dem optionalen (-W.*)? den letzten Text verschlingt. Die Verwendung eines nicht gierigen Spiels hilft auch nicht. Meine Regex-Fu ist leider zu schwach, um dies zu bekämpfen.

Wenn Ihnen eine Multi-Pass-Lösung nichts ausmacht, dann wäre ein einfacherer Ansatz, zuerst die Eingabe zu bereinigen, indem Sie die nachfolgenden .raw.gz und möglichen -W* entfernen.

str="20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz" 
echo ${str%.raw.gz} | # remove trailing .raw.gz 
    sed 's/-W.*$//' | # remove trainling -W.*, if any 
    sed -nr 's/[0-9]{8}_M[0-9]_[0-9]{8}\.[0-9]{3}_._(.*)/\1/p' 

Ich habe sed verwendet, aber Sie können auch gawk/awk verwenden.

0

war nicht in der Lage nur ungern quantifiers gehen, zu erhalten, aber durch zwei reguläre Ausdrücke in der Reihenfolge ausgeführt hat den Zweck erfüllt:

sed -E -e 's/^.{27}(.*).raw.gz$/\1/' << FOO | sed -E -e 's/-W[0-9.]+\+[0-9.]+$//' 
20100613_M4_28007834.005_F_SOME-STRING.raw.gz 
20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz 
FOO 
+1

'sed -E/(- W [0-9]. [0-9] {2}. [0-9] {3})?.. Root \ .gz $ //; s /.* _ // ''... Du brauchst nicht mehrere Rohre. (Für alle Linux-Benutzer verwenden Sie 'sed -r' anstelle von' sed-E'). – ghoti

+0

Ja, ganz richtig. sed -e nimmt eine Befehlsfolge entgegen. Ich sollte eines meiner Skripte neu schreiben :) – PaulMurrayCbr

1

Während die grep Lösung in der Tat sehr schön, nicht die OP erwähnen ein Betriebssystem, und die Option -P scheint nur unter Linux verfügbar zu sein. Es ist auch ziemlich einfach, dies in awk zu tun.

$ awk -F_ '{sub(/(-W[0-9].[0-9]+.[0-9]+)?\.raw\.gz$/,"",$NF); print $NF}' <<EOT 
> 20100613_M4_28007834.005_F_SOME-STRING.raw.gz 
> 20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz 
> EOT 
SOME-STRING 
OTHER-STRING 
$ 

Beachten Sie, dass diese bricht auf "20100613_M4_28007834.005_F_OTHER-STRING-W0_40 + 045.raw.gz". Wenn dies ein Risiko ist, und -W zeigt nur an dem Ort, oben gezeigt, könnte es besser sein, etwas zu verwenden wie:

$ awk -F_ '{sub(/(-W[0-9.+]+)?\.raw\.gz$/,"",$NF); print $NF}'