Je vois beaucoup d'exemples et de pages de manuel sur la façon de faire des choses comme rechercher et remplacer en utilisant sed, awk ou gawk.
Mais dans mon cas, j'ai une expression régulière que je souhaite exécuter sur un fichier texte pour extraire une valeur spécifique. Je ne veux pas faire de recherche et de remplacement. Ceci est appelé de bash. Prenons un exemple:
Exemple d'expression régulière:
.*abc([0-9]+)xyz.*
Exemple de fichier d'entrée:
a
b
c
abc12345xyz
a
b
c
Aussi simple que cela puisse paraître, je ne peux pas comprendre comment appeler correctement sed / awk / gawk. Ce que j'espérais faire, c'est de l'intérieur de mon script bash avoir:
myvalue=$( sed <...something...> input.txt )
Les choses que j'ai essayées incluent:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Réponses:
Mon
sed
(Mac OS X) ne fonctionnait pas avec+
. J'ai essayé à la*
place et j'ai ajouté unep
étiquette pour l'impression du match:Pour faire correspondre au moins un caractère numérique sans
+
, j'utiliserais:la source
+
et puis cela a fonctionné pour moi:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Vous pouvez utiliser sed pour ce faire
-n
ne pas imprimer la ligne résultante-r
cela fait en sorte que vous n'ayez pas l'échappement des parens du groupe de capture()
.\1
le match de groupe de capture/g
match global/p
imprimer le résultatJ'ai écrit un outil pour moi-même qui facilite cela
la source
J'utilise
perl
pour me faciliter la tâche. par exempleCela exécute Perl, l'
-n
option demande à Perl de lire une ligne à la fois depuis STDIN et d'exécuter le code. L'-e
option spécifie l'instruction à exécuter.L'instruction exécute une expression rationnelle sur la ligne lue et, si elle correspond, affiche le contenu du premier ensemble de crochets (
$1
).Vous pouvez le faire avec plusieurs noms de fichiers à la fin également. par exemple
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
la source
Si votre version de le
grep
prend en charge, vous pouvez utiliser l'-o
option pour n'imprimer que la partie de toute ligne qui correspond à votre expression régulière.Sinon, voici le meilleur que
sed
je pourrais trouver:... qui supprime / saute sans chiffres et, pour les lignes restantes, supprime tous les caractères non numériques de début et de fin. (Je suppose seulement que votre intention est d'extraire le numéro de chaque ligne qui en contient un).
Le problème avec quelque chose comme:
.... ou
... est que
sed
ne prend en charge que la correspondance "gourmande" ... donc le premier. * correspondra au reste de la ligne. À moins que nous ne puissions utiliser une classe de caractères annulée pour obtenir une correspondance non gourmande ... ou une version desed
avec Perl compatible ou d'autres extensions de ses expressions rationnelles, nous ne pouvons pas extraire une correspondance de motif précise à partir de l'espace de motif (une ligne ).la source
sed
commandes de cette manière:sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! J'essayais de le fairesed
et j'ai eu du mal avec mon besoin de trouver plusieurs correspondances sur certaines lignes. Ma solution est stackoverflow.com/a/58308239/117471Vous pouvez utiliser
awk
avecmatch()
pour accéder au groupe capturé:Cela tente de correspondre au modèle
abc[0-9]+xyz
. Si tel est le cas, il stocke ses tranches dans le tableaumatches
, dont le premier élément est le bloc[0-9]+
. Puisquematch()
renvoie la position du caractère, ou l'index, d'où commence cette sous-chaîne (1, si elle commence au début de la chaîne) , il déclenche l'print
action.Avec,
grep
vous pouvez utiliser un regard en arrière et un regard en avant:Cela vérifie le modèle
[0-9]+
lorsqu'il se produit dansabc
etxyz
et imprime simplement les chiffres.la source
perl est la syntaxe la plus propre, mais si vous n'avez pas perl (pas toujours là, je comprends), alors la seule façon d'utiliser gawk et les composants d'une regex est d'utiliser la fonction gensub.
la sortie de l'échantillon de fichier d'entrée sera
Remarque: gensub remplace l'ensemble de l'expression régulière (entre //), donc vous devez mettre le. * Avant et après le ([0-9] +) pour supprimer le texte avant et après le nombre dans la substitution.
la source
match()
pour accéder aux groupes capturés. Voir ma réponse à ce sujet.Si vous voulez sélectionner des lignes, supprimez les bits que vous ne voulez pas:
Il sélectionne essentiellement les lignes que vous voulez avec
egrep
, puis les utilisesed
pour supprimer les bits avant et après le nombre.Vous pouvez voir cela en action ici:
Mise à jour: évidemment si votre situation actuelle est plus complexe, les RE devront être modifiés. Par exemple, si vous aviez toujours un seul nombre enterré entre zéro ou plusieurs non-numériques au début et à la fin:
la source
Le cas de l'OP ne spécifie pas qu'il peut y avoir plusieurs correspondances sur une seule ligne, mais pour le trafic Google, j'ajouterai également un exemple pour cela.
Puisque le besoin du PO est d'extraire un groupe d'un motif, l'utilisation
grep -o
nécessitera 2 passes. Mais je trouve toujours que c'est le moyen le plus intuitif de faire le travail.Étant donné que le temps processeur est fondamentalement gratuit mais que la lisibilité humaine n'a pas de prix, j'ai tendance à refactoriser mon code en me basant sur la question "dans un an, qu'est-ce que je vais penser que cela fait?" En fait, pour le code que j'ai l'intention de partager publiquement ou avec mon équipe, je vais même ouvrir
man grep
pour comprendre quelles sont les options longues et les remplacer. Ainsi:grep --only-matching --extended-regexp
la source
vous pouvez le faire avec la coque
la source
Pour awk. J'utiliserais le script suivant:
la source
([0-9+])
, cela génère la ligne entière.la source