Anpassen eines spezifischen mit regulären Ausdrücken String awk mit
Frage
Ich bin der Umgang mit einem bestimmten Dateinamen und Notwendigkeit, Informationen von ihnen zu extrahieren.
Die Struktur des Dateinamens ist ähnlich: "20100613_M4_28007834.005_F_RANDOMSTR.raw.gz"
mit RandomStr eine Kette von max 22 Zeichen, und die eine Teilkette (oder nicht) mit dem Format enthalten können „-W [0-9]. [0-9] {2}. [0-9] {3 }“. Dieses substring hat auch die einzigartige Eigenschaft, die mit „-W“.
Die Informationen, die ich zu extrahieren muß, ist der Teil von RandomStr ohne diese optionale Teilkette.
Ich möchte dies in einem Bash-Skript implementieren und so weit die beste Option, ich fand, ist gaffen 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 erzielen.
Danke.
Lösung
Sie müssen in der Lage sein Blick Arounds zu verwenden, und ich glaube nicht, awk / gawk unterstützt das, aber grep -P
der Fall ist.
$ 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
Andere Tipps
Während die grep Lösung wirklich sehr schön ist, hat der OP kein Betriebssystem erwähnen, und die -P
Option scheint nur unter Linux zur Verfügung zu stehen. Es ist auch ziemlich einfach dieses 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 dieser bricht auf "20100613_M4_28007834.005_F_OTHER-STRING-W0_40 + 045.raw.gz". Wenn dies ein Risiko ist, und -W
zeigt nur oben an der Stelle nach oben gezeigt, könnte es sein, besser zu nutzen so etwas wie:
$ awk -F_ '{sub(/(-W[0-9.+]+)?\.raw\.gz$/,"",$NF); print $NF}'
Die Schwierigkeit scheint die Tatsache zu sein, dass die (.*)
vor dem optionalen (-W.*)?
verschlingt letztere Text auf. ein nicht gieriges Spiel unter Verwendung von nicht hilft auch nicht. Mein regex-fu leider zu schwach ist, um diese zu bekämpfen.
Wenn Sie nicht eine Multi-Pass-Lösung nichts dagegen haben, dann ist ein einfacher Ansatz zur ersten sanitize der Eingang würde durch die hinteren .raw.gz
und mögliche -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'
Früher habe ich sed, aber man kann genauso gut verwenden gawk / awk.
War nur ungern quantifiers gehen, bekommen nicht in der Lage, sondern läuft durch zwei reguläre Ausdrücke in Folge 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