Réponses:
La clé pour que cela fonctionne est de dire sed
d'exclure ce que vous ne voulez pas sortir et de spécifier ce que vous voulez.
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Cela dit:
-n
)p
)En général, dans sed
vous capturez des groupes à l'aide de parenthèses et sortez ce que vous capturez à l'aide d'une référence arrière:
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
affichera "bar". Si vous utilisez -r
( -E
pour OS X) pour l'expression régulière étendue, vous n'avez pas besoin d'échapper aux parenthèses:
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
Il peut y avoir jusqu'à 9 groupes de capture et leurs références arrières. Les références arrières sont numérotées dans l'ordre d'apparition des groupes, mais elles peuvent être utilisées dans n'importe quel ordre et peuvent être répétées:
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
affiche "une barre a".
Si vous avez GNU grep
(il peut également fonctionner dans BSD, y compris OS X):
echo "$string" | grep -Po '\d+'
ou des variations telles que:
echo "$string" | grep -Po '(?<=\D )(\d+)'
L' -P
option active les expressions régulières compatibles Perl. Voir man 3 pcrepattern
ou man
3 pcresyntax
.
sed
exemple, si vous utilisez l' -r
option (ou -E
pour OS X, IIRC), vous n'avez pas besoin d'échapper aux parenthèses. La différence est celle entre les expressions régulières de base et les expressions régulières étendues ( -r
).
Sed a jusqu'à neuf modèles mémorisés, mais vous devez utiliser des parenthèses d'échappement pour mémoriser des parties de l'expression régulière.
Voir ici pour des exemples et plus de détails
sed -e 's/version=\(.+\)/\1/' input.txt
cela affichera toujours le fichier input.txt entier
\+
au lieu de +
. Et je ne comprends pas pourquoi les gens utilisent -e
pour une seule commande sed.
sed -e -n 's/version=\(.+\)/\1/p' input.txt
voir: mikeplate.com/2012/05/09/…
sed -E
d'utiliser les expressions régulières dites "modernes" ou "étendues" qui ressemblent beaucoup plus à Perl / Java / JavaScript / Go / quelles que soient les saveurs. (Comparez avec grep -E
ou egrep
.) La syntaxe par défaut a ces étranges règles d'échappement et est considérée comme "obsolète". Pour plus d'informations sur les différences entre les deux, exécutez man 7 re_format
.
vous pouvez utiliser grep
grep -Eow "[0-9]+" file
o
option est là - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, --only-matching N'afficher que la partie d'une ligne correspondante qui correspond au MOTIF
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
je ne sais pas comment vous pourriez exiger que ces deux expressions soient sur une seule ligne en dehors de la tuyauterie d'un grep précédent (qui pourrait toujours ne pas fonctionner si l'un des motifs correspond plus d'une fois sur une ligne ).
Cette réponse fonctionne avec n'importe quel nombre de groupes de chiffres. Exemple:
$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Existe-t-il un moyen de dire à sed de sortir uniquement les groupes capturés?
Oui. remplacer tout le texte par le groupe de capture:
$ echo 'Number 123 inside text' | sed 's/[^0-9]*\([0-9]\{1,\}\)[^0-9]*/\1/'
123
s/[^0-9]* # several non-digits
\([0-9]\{1,\}\) # followed by one or more digits
[^0-9]* # and followed by more non-digits.
/\1/ # gets replaced only by the digits.
Ou avec une syntaxe étendue (moins de guillemets et autorise l'utilisation de +):
$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123
Pour éviter d'imprimer le texte d'origine lorsqu'il n'y a pas de numéro, utilisez:
$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
Et pour faire correspondre plusieurs nombres (et aussi les imprimer):
$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456
Cela fonctionne pour n'importe quel nombre d'exécutions de chiffres:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Ce qui est très similaire à la commande grep:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166
et motif:
/([\d]+)/
Sed ne reconnaît pas la syntaxe '\ d' (raccourci). L'équivalent ascii utilisé ci [0-9]
- dessus n'est pas exactement équivalent. La seule solution alternative consiste à utiliser une classe de caractères: '[[: digit:]] `.
La réponse sélectionnée utilise ces "classes de caractères" pour construire une solution:
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Cette solution ne fonctionne que pour (exactement) deux séries de chiffres.
Bien sûr, comme la réponse est exécutée à l'intérieur du shell, nous pouvons définir quelques variables pour raccourcir cette réponse:
$ str='This is a sample 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*/\1 \2/p"
Mais, comme cela a déjà été expliqué, l'utilisation d'une s/…/…/gp
commande est préférable:
$ str='This is 75577 a sam33ple 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D*/\1 /gp"
75577 33 123 987
Cela couvrira les deux séries répétées de chiffres et l'écriture d'une commande courte (er).
Je crois que le modèle donné dans la question était à titre d'exemple uniquement, et le but était de correspondre à n'importe quel modèle.
Si vous avez un sed avec l'extension GNU permettant l'insertion d'une nouvelle ligne dans l'espace de motif, une suggestion est:
> set string = "This is a sample 123 text and some 987 numbers"
>
> set pattern = "[0-9][0-9]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
123
987
> set pattern = "[a-z][a-z]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
his
is
a
sample
text
and
some
numbers
Ces exemples sont avec tcsh (oui, je sais que c'est le mauvais shell) avec CYGWIN. (Modifier: pour bash, supprimez l'ensemble et les espaces autour de =.)
+
, vous devez l'échapper ou utiliser l' -r
option ( -E
pour OS X). Vous pouvez également utiliser \{1,\}
(ou -r
ou -E
sans l'échappement).
Abandonnez et utilisez Perl
Puisque sed
ne le coupe pas, jetons simplement la serviette et utilisons Perl, au moins c'est LSB alors que les grep
extensions GNU ne le sont pas :-)
Imprimez l'intégralité de la partie correspondante, pas de groupes correspondants ou de recherche nécessaire:
cat <<EOS | perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
Production:
12
3456
Correspondance unique par ligne, champs de données souvent structurés:
cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
Production:
1
34
Avec lookbehind:
cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
Champs multiples:
cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
Production:
1 2
34 56
Correspondances multiples par ligne, données souvent non structurées:
cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
a1 b2
a34 b56 a78 b90
EOS
Production:
1
34 78
Avec lookbehind:
cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
Production:
1
3478
Essayer
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
J'ai obtenu ceci sous cygwin:
$ (echo "asdf"; \
echo "1234"; \
echo "asdf1234adsf1234asdf"; \
echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
1234
1234 1234
1 2 3 4 5 6 7 8 9
$
Ce n'est pas ce que l'OP a demandé (capture de groupes) mais vous pouvez extraire les chiffres en utilisant:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
Donne ce qui suit:
123
987
sed
d'activer les expressions régulières étendues avec l'-E
indicateur.