Existe-t-il un moyen de dire à sed
de ne générer que les groupes capturés? Par exemple, étant donné l'entrée:
This is a sample 123 text and some 987 numbers
et motif:
/([\d]+)/
Pourrais-je obtenir uniquement les sorties 123 et 987 de la même manière que les références arrières?
La clé pour que cela fonctionne est de dire à sed
d'exclure ce que vous ne voulez pas afficher, ainsi que 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 vous affichez 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 les expressions rationnelles étendues, 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ère 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
(cela peut également fonctionner sous BSD, y compris OS X):
_echo "$string" | grep -Po '\d+'
_
ou des variations telles que:
_echo "$string" | grep -Po '(?<=\D )(\d+)'
_
L'option _-P
_ active les expressions régulières compatibles Perl. Voir man 3 pcrepattern
ou man 3 pcresyntax
.
Sed a mémorisé jusqu'à neuf modèles, mais vous devez utiliser des parenthèses insérées pour mémoriser des parties de l'expression régulière.
Voir ici pour des exemples et plus de détails
vous pouvez utiliser grep
grep -Eow "[0-9]+" file
Abandonnez et utilisez Perl
Puisque sed
ne le coupe pas, jetons simplement la serviette et utilisons Perl, du moins c'est LSB alors que grep
GNU les extensions ne sont pas :-)
Imprimez l'intégralité de la pièce correspondante. Aucun groupe ni aucune recherche ne sont nécessaires:
cat <<EOS | Perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
Sortie:
12
3456
Correspondance simple par ligne, champs de données souvent structurés:
cat <<EOS | Perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
Sortie:
1
34
À regarder derrière:
cat <<EOS | Perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
Plusieurs champs:
cat <<EOS | Perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
Sortie:
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
Sortie:
1
34 78
À regarder derrière:
cat EOS<< | Perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
Sortie:
1
3478
Je crois que le modèle donné dans la question était à titre d'exemple uniquement, et le but était de faire correspondre le modèle any .
Si vous avez une extension sed avec l’extension GNU permettant l’insertion d’une nouvelle ligne dans l’espace du motif, voici une suggestion:
> 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 c'est le mauvais shell) avec CYGWIN. (Edit: pour bash, supprimez set et les espaces autour de =.)
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
Est-il possible d'indiquer à sed de ne produire que les groupes capturés?
Oui. remplace 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 permettent 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 original en l’absence 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 numéros (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-dessus [0-9]
n'est pas exactement équivalent. La seule solution consiste à utiliser une classe de caractères: '[[: digit:]] `.
La réponse sélectionnée utilise de telles "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, étant donné que la réponse est en cours d'exécution dans le 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 commande s/…/…/gp
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 passages répétés de chiffres et l’écriture d’une commande plus courte.
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"
Je l'ai 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é (capturer des groupes) mais vous pouvez extraire les nombres 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