168 votes

sed : imprimer seulement le groupe correspondant

Je veux saisir les deux derniers chiffres (un int, un float ; suivi d'un espace optionnel) et les imprimer uniquement.

Exemple :

foo bar <foo> bla 1 2 3.4

Il faut imprimer :

2 3.4

Pour l'instant, j'ai les éléments suivants :

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

me donnera

foo bar <foo> bla 1 replacement

Cependant, si j'essaie de le remplacer par le groupe 1, la ligne entière est imprimée.

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

Comment puis-je imprimer uniquement la section de la ligne qui correspond à l'expression rationnelle dans le groupe ?

177voto

1_CR Points 11848

Faites correspondre la ligne entière, donc ajoutez un .* au début de votre expression rationnelle. Ainsi, la ligne entière sera remplacée par le contenu du groupe

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

83voto

Kent Points 71470

grep est le bon outil pour extraire.

en utilisant votre exemple et votre regex :

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

13voto

chooban Points 2851

Et pour une autre option, je choisirais awk !

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

Ceci va diviser l'entrée (j'utilise STDIN ici, mais votre entrée pourrait facilement être un fichier) en espaces, et ensuite imprimer l'avant-dernier champ, et ensuite le dernier champ. Le site $NF Les variables contiennent le nombre de champs trouvés après l'éclatement sur les espaces.

L'avantage de cette méthode est que peu importe si ce qui précède les deux derniers champs change, tant que vous ne voulez que les deux derniers, cela continuera à fonctionner.

7voto

carlin.scott Points 145

La commande cut est conçue pour cette situation exacte. Elle "coupe" sur n'importe quel délimiteur et vous pouvez ensuite spécifier quels morceaux doivent être sortis.

Par exemple : echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Il en résultera une sortie de : 2 3.4

-d définit le délimiteur

-f sélectionne la plage de 'champs' à sortir, dans ce cas, ce sont les 6ème et 7ème morceaux de la chaîne originale. Vous pouvez également spécifier l'intervalle sous forme de liste, par exemple 6,7 .

7voto

Richard Bronosky Points 3163

Je suis d'accord avec @kent que cela convient bien à grep -o . Si vous devez extraire un groupe à l'intérieur d'un motif, vous pouvez le faire avec un second grep.

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9

En général, j'ai un mouvement de recul lorsque je vois deux appels à grep/sed/awk réunis dans un même tuyau, mais ce n'est pas toujours une erreur. Bien que nous devions exercer nos compétences pour faire les choses de manière efficace, "Une cohérence stupide est le hobgobelin des petits esprits", et "Les vrais artistes naviguent".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X