J'utilise GNU grep
avec la prise en charge de -P
PCRE Regex pour faire correspondre les strings à partir d'un file. Le file d'input contient des lignes contenant des strings comme:
FOO_1BAR.zoo.2.someSsortingng:More-RandomSsortingng (ssortingng here too): 0.45654343
Je veux capturer les numéros 2
et 0.45654343
de la ligne ci-dessus. J'ai utilisé un regEx
grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file
Mais cela me donne un résultat
2.someSsortingng:More-RandomSsortingng (ssortingng here too): 0.45654343
Je suis capable d'get le premier nombre du premier groupe de capture comme 2
, et aussi de faire correspondre un groupe de capture à la fin de la ligne. Mais je ne suis pas capable de passer les mots / lignes entre deux groupes de capture.
Je sais pertinemment que j'ai un groupe (.*)
Qui capture ces mots au milieu. Ce que j'ai essayé de faire est d'inclure un autre \K
pour l'ignorer
grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file
Mais cela m'a donné seulement le deuxième groupe de capture comme 0.556984
.
Aussi avec un groupe non-capture avec la syntaxe (?:)
comme
grep -Po ".zoo.\K[\d+](?=.someSsortingng:More-RandomSsortingng (ssortingng here too)):\ (.*)$"
Mais cela ne m'a rien donné. Qu'est-ce que j'oublie ici?
Le nom de grep
vient après la command g/re/p
ed
. Son but principal est d'imprimer les lignes qui correspondent à une expression rationnelle. Ce n'est pas son rôle d'éditer le contenu de ces lignes. Vous avez sed
(l'éditeur de stream) ou awk
pour cela.
Maintenant, certaines implémentations grep
, en commençant par GNU grep
ajouté une option -o
pour imprimer la partie appariée de chaque ligne (ce qui correspond à l'expression rationnelle, et non à ses groupes de capture). Vous avez une implémentation grep
comme GNU à nouveau (avec -P
) ou pcregrep
qui supporte les PCRE pour leurs expressions rationnelles.
pcregrep
fait ajouté une option -o<n>
pour imprimer le contenu d'un groupe de capture. Donc, vous pourriez faire:
pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'
Mais ici, la solution standard évidente est d'utiliser sed
:
sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'
Ou si vous voulez perl regexps, utilisez perl:
perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'
Avec GNU grep
, si vous ne vous occupez pas des apparences sur différentes lignes, vous pouvez faire:
$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file 2 0.45654343
Notez que while \K
réinitialise le début de la partie appariée, cela ne signifie pas que vous pouvez vous en sortir avec les deux parties de l'alternance qui se chevauchent.
grep -Po '.zoo. (\ K \ d + | .: \ K. )'
ne fonctionnerait pas, tout comme echo foobar | grep -Po 'foo|foob'
echo foobar | grep -Po 'foo|foob'
ne fonctionnerait pas (en imprimant à la fois foo
et foob
). foo|foob
abord correspondre foo
et ensuite grep
search d'autres correspondances potentielles dans l'input après le foo
, donc en commençant par le b
de la bar
, donc ne peut plus en find.
En haut avec grep -Po '\.zoo\.\K\d+|:\s+\K.*'
, nous recherchons seulement :<spaces><anything>
dans la deuxième partie de l'alternance. Cela correspond à la partie qui se trouve après .zoo.<digits>
mais cela signifie aussi qu'elle findait :<spaces><anything>
n'importe où dans l'input, pas seulement quand ils suivent .zoo.<digits>
.
Il existe cependant un moyen de contourner ce problème en utilisant un autre opérateur spécial PCRE: \G
\G
correspond au début du sujet. Pour une seule correspondance, cela équivaut à ^
, mais avec plusieurs correspondances (pensez au drapeau g
de sed
/ perl
dans s/.../.../g
) comme avec -o
où grep
essaye de find toutes les correspondances dans la ligne, qui correspond également après la fin du match précédent. Donc, si vous le faites:
grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
Où (?!^)
Est un opérateur de look-ahead négatif qui ne signifie pas au début de la ligne , que \G
ne correspondra qu'après un succès précédent (non vide), donc .*:\s+\K.*
ne correspondra que si elle suit une correspondance réussie précédente et qui ne peut être que le .foo.<digits>
car l'autre partie de l'alternance correspond à la fin de la ligne.
Sur une input comme:
.zoo.1.zoo.2 tar: blah
Cela donnerait:
1 2 blah
Bien que. Si vous ne le vouliez pas, vous souhaiteriez également que la première partie de l'alternance ne corresponde qu'au début de la ligne. Quelque chose comme
grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
Cela produit toujours 2
sur une input comme .zoo.2 no colon character
ou .zoo.2 blah:
Vous pouvez travailler avec un opérateur de search anticipée dans la première partie de l'alternance et searchr au less un non-espace après :<spaces>
(et aussi en utilisant $
pour éviter les problèmes avec des non-caractères)
grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
Vous auriez probablement besoin de quelques pages de commentaires pour expliquer cette regexp, alors j'irais toujours pour les solutions straightfoward sed
/ perl
…