2010-12-15 84 views
3

J'ai affaire à un nom de fichier spécifique, et j'ai besoin d'en extraire des informations.correspondant à une sous-chaîne spécifique avec des expressions régulières en utilisant awk

La structure du nom de fichier est similaire à: « 20100613_M4_28007834.005_F_RANDOMSTR.raw.gz »

avec RANDOMSTR une chaîne de 22 caractères maximum, et qui peut contenir une sous-chaîne (ou non) avec le format « - W [0-9]. [0-9] {2}. [0-9] {3} ". Cette sous-chaîne a également la particularité de commencer par "-W".

L'information dont j'ai besoin d'extraire est la sous-chaîne de RANDOMSTR sans cette sous-chaîne optionnelle. Je veux implémenter ceci dans un script bash, et jusqu'ici la meilleure option que j'ai trouvée est d'utiliser gawk avec une expression régulière. Ma meilleure tentative échoue si loin:

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 

Les résultats attendus sont:

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 

Comment puis-je obtenir l'effet désiré.

Merci.

+0

Vous avez dit que la sous-chaîne a le motif '" -W [0-9]. [0-9] {2}. [0-9] {3} "' Pourtant, votre exemple d'entrée contient '... W0.40 + 045.raw.gz'. Avez-vous besoin de répondre aux deux? –

+0

Je n'inclue pas le fichier ".raw.gz" dans la sous-chaîne. – RogerFC

+0

Désolé, je voulais attirer l'attention sur le signe plus qui ne serait pas couvert par votre motif. –

Répondre

2

Vous devez être capable d'utiliser des look-arounds et je ne pense pas que awk/gawk supporte cela, mais grep -P le fait.

$ 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

C'est vraiment plus fort regex-fu! +1 –

+1

btw, ne fonctionne pas pour moi sauf si je le change en 'pat = '(? <= [0-9] {8} _M [0-9] _ [0-9] {8} \. [0 -9] {3} _._) (. +?) (? = (- W. *)? \. Raw \ .gz) '', c'est-à-dire que je devais utiliser' (. +?) 'Au lieu de' (. *?) '. –

+0

@Shawn: '(. +?)' Est probablement meilleur, mais cela fonctionne pour moi comme indiqué. J'ai juste copié et collé les lignes de ma réponse pour le tester à nouveau et ça marche (dans tous les cas). –

0

La difficulté ici semble être le fait que le (.*) avant la (-W.*)? option gobe le dernier texte. Utiliser un match non gourmand n'aide pas non plus. Mon regex-fu est malheureusement trop faible pour combattre ça. Si une solution multi-passes ne vous dérange pas, alors une approche plus simple consisterait à désinfecter l'entrée en supprimant .raw.gz et -W*.

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' 

J'ai utilisé sed, mais vous pouvez aussi utiliser gawk/awk.

0

n'a pas pu obtenir quantificateurs réticents aller, mais en cours d'exécution à travers deux expressions rationnelles dans l'ordre fait le travail:

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 's/(-W [0-9]. [0-9] {2}. [0-9] {3})? \. Raw \ .gz $ //; s /.* _ // ''... Vous n'avez pas besoin de plusieurs tuyaux. (Pour tous les utilisateurs de Linux, utilisez 'sed -r' au lieu de' sed -E'.) – ghoti

+0

Oui, tout à fait raison. sed -e prendra une séquence de commandes. Je devrais réécrire l'un de mes scripts :) – PaulMurrayCbr

1

Alors que la solution de grep est très agréable en effet, l'OP n'a pas mentionné un système d'exploitation, et l'option -P semble seulement être disponible sous Linux. C'est aussi très simple de faire ça dans awk.

$ 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 
$ 

Notez que ce casse sur "20100613_M4_28007834.005_F_OTHER-STRING-W0_40 + 045.raw.gz". Si cela est un risque, et -W ne se présente à l'endroit indiqué ci-dessus, il pourrait être préférable d'utiliser quelque chose comme:

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