Il y a deux façons d'interpréter cette question. Je vais aborder les deux cas. Vous voudrez peut-être afficher des lignes:
- qui contiennent une séquence de quatre chiffres qui ne fait pas partie d'une séquence de chiffres plus longue, ou
- qui contient une séquence de quatre chiffres mais plus une séquence de chiffres (même pas séparément).
Par exemple, (1) devrait s'afficher 1234a56789
, mais pas (2).
Si vous souhaitez afficher toutes les lignes contenant une séquence de quatre chiffres qui ne fait pas partie d'une séquence de chiffres plus longue, procédez comme suit:
grep -P '(?<!\d)\d{4}(?!\d)' file
Cela utilise des expressions régulières Perl , que Ubuntu grep
( GNU grep ) prend en charge via -P
. Il ne correspond pas à texte comme 12345
, ni ne correspond au 1234
ou 2345
qui font partie de celui - ci. Mais elle correspondra 1234
à 1234a56789
.
Dans les expressions rationnelles Perl:
\d
signifie n'importe quel chiffre (c'est un moyen court de dire [0-9]
ou [[:digit:]]
).
x{4}
correspond x
4 fois. (La {
}
syntaxe n'est pas spécifique aux expressions rationnelles Perl; elle s'applique grep -E
aussi bien aux expressions rationnelles étendues .) Ainsi, \d{4}
est identique à \d\d\d\d
.
(?<!\d)
est une assertion de recherche négative de largeur nulle. Cela signifie "à moins d'être précédé de \d
".
(?!\d)
est une assertion d'anticipation négative de largeur nulle. Cela signifie "sauf si suivi de \d
".
(?<!\d)
et (?!\d)
ne correspond pas au texte en dehors de la séquence de quatre chiffres; au lieu de cela, ils empêcheront (lorsqu'ils sont utilisés ensemble) d'empêcher l'appariement d'une séquence de quatre chiffres s'il fait partie d'une séquence de chiffres plus longue.
Utiliser uniquement le regard en arrière ou juste en avant est insuffisant, car la sous-séquence à quatre chiffres la plus à droite ou la plus à gauche serait toujours appariée.
L'un des avantages des assertions d'anticipation et d'anticipation est que votre modèle correspond uniquement aux séquences à quatre chiffres elles-mêmes, et non au texte environnant. Ceci est utile lorsque vous utilisez la mise en surbrillance des couleurs (avec l' --color
option).
ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4
Par défaut, dans Ubuntu, chaque utilisateur a alias grep='grep --color=auto'
son ~.bashrc
fichier . Ainsi, la couleur est surlignée automatiquement lorsque vous exécutez une commande simple commençant par grep
(c'est-à-dire lorsque les alias sont développés) et la sortie standard est un terminal (c'est ce que vérifie). Les allumettes sont généralement surlignées en rouge (proche du vermillon ), mais je les ai montrées en italiques gras. Voici une capture d'écran:--color=auto
Et vous pouvez même grep
imprimer uniquement le texte correspondant, et non la ligne entière, avec -o
:
ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123
Manière alternative, sans assertions de Look-Behind and Look-Ahead
Cependant, si vous:
- besoin d'une commande qui s'exécutera également sur des systèmes où
grep
ne prend pas en charge -P
ou ne souhaite pas utiliser une expression régulière Perl, et
- vous n'avez pas besoin de faire correspondre spécifiquement les quatre chiffres - ce qui est généralement le cas si votre objectif est simplement d'afficher des lignes contenant des correspondances, et
- sont d'accord avec une solution un peu moins élégante
... vous pouvez y parvenir avec une expression régulière étendue :
grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file
Cela correspond à quatre chiffres et au caractère non numérique - ou au début ou à la fin de la ligne - qui les entoure. Plus précisément:
[0-9]
correspond à un chiffre (comme [[:digit:]]
, ou \d
en Perl des expressions régulières) et {4}
signifie « quatre fois ». Correspond donc à [0-9]{4}
une séquence de quatre chiffres.
[^0-9]
correspond aux caractères pas dans la plage de 0
travers 9
. Cela équivaut à [^[:digit:]]
(ou \D
, dans les expressions rationnelles Perl).
^
, quand il n'apparaît pas [
]
entre parenthèses, correspond au début d'une ligne. De même, $
correspond à la fin d'une ligne.
|
les moyens ou et les parenthèses sont à regrouper (comme en algèbre). Correspond donc (^|[^0-9])
au début de la ligne ou à un caractère non numérique, alors que ($|[^0-9])
correspond à la fin de la ligne ou à un caractère non numérique.
Les correspondances ne se produisent donc que dans les lignes contenant une séquence à quatre chiffres ( [0-9]{4}
) qui est simultanément:
- au début de la ligne ou précédé d'un non-chiffre (
(^|[^0-9])
), et
- à la fin de la ligne ou suivi d’un non-chiffre (
($|[^0-9])
).
Si, en revanche, vous souhaitez afficher toutes les lignes contenant une séquence de quatre chiffres, mais ne contenant aucune séquence de plus de quatre chiffres (même une séquence distincte d'une autre séquence de quatre chiffres seulement), votre concept L’objectif est de trouver des lignes qui correspondent à un motif mais pas à un autre.
Par conséquent, même si vous savez comment faire avec un seul motif, je vous suggérerais d'utiliser quelque chose comme la deuxième suggestion de matt , grep
pour les deux motifs séparément.
Lorsque vous le faites, vous ne bénéficiez d'aucune des fonctionnalités avancées des expressions régulières Perl. Par conséquent, vous préférerez peut-être ne pas les utiliser. Mais en accord avec le style ci-dessus, voici un raccourcissement de la solution de matt en utilisant \d
(et des accolades) à la place de [0-9]
:
grep -P '\d{4}' file | grep -Pv '\d{5}'
Comme il utilise [0-9]
, la manière de mat est plus portable - il fonctionnera sur les systèmes où grep
ne prennent pas en charge les expressions régulières Perl. Si vous utilisez [0-9]
(ou [[:digit:]]
) au lieu de \d
, mais continuez à utiliser {
}
, vous obtenez la portabilité de la manière de matt un peu plus concise:
grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'
Manière alternative, avec un motif simple
Si vous préférez vraiment une grep
commande qui
- utilise une seule expression rationnelle (pas deux
grep
s séparés par un tuyau , comme ci-dessus)
- pour afficher des lignes contenant au moins une séquence de quatre chiffres,
- mais pas de séquences de cinq chiffres (ou plus),
- et cela ne vous dérange pas de faire correspondre toute la ligne, pas seulement les chiffres (cela ne vous dérange probablement pas)
... alors vous pouvez utiliser:
grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file
L' -x
indicateur fait en grep
sorte que seules les lignes correspondant à la totalité de la ligne soient affichées (plutôt que toute ligne contenant une correspondance).
J'ai utilisé une expression régulière Perl parce que je pense que la brièveté \d
et l' \D
augmentation de la clarté dans le cas présent. Mais si vous avez besoin de quelque chose de portable pour des systèmes sur lesquels grep
ne prend pas en charge -P
, vous pouvez les remplacer par [0-9]
et [^0-9]
(ou avec [[:digit:]]
et [^[:digit]]
):
grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file
La façon dont ces expressions régulières fonctionnent est la suivante:
Au milieu \d{4}
ou [0-9]{4}
correspond à une séquence de quatre chiffres. Nous pouvons en avoir plusieurs, mais nous devons en avoir au moins un.
Sur la gauche, (\d{0,4}\D)*
ou ([0-9]{0,4}[^0-9])*
correspond à zéro ou plus ( *
) instances de pas plus de quatre chiffres suivies d'un non-chiffre. Zéro chiffre (c'est-à-dire rien) est une possibilité pour "pas plus de quatre chiffres". Cela correspond (a) à la chaîne vide ou (b) à toute chaîne se terminant par un non-chiffre et ne contenant aucune séquence de plus de quatre chiffres.
Etant donné que le texte situé immédiatement à gauche de la lettre centrale \d{4}
(ou [0-9]{4}
) doit être vide ou se terminer par un non-chiffre, cela empêche la centrale \d{4}
de faire correspondre quatre chiffres comportant un autre (cinquième) chiffre juste à gauche d'eux.
À droite, (\D\d{0,4})*
ou ([^0-9][0-9]{0,4})*
correspond à zéro ou plusieurs *
occurrences ( ) d'un non-chiffre suivi de quatre chiffres au maximum (qui, comme auparavant, pourrait être quatre, trois, deux, un, voire même aucun). Cela correspond (a) à la chaîne vide ou (b) à toute chaîne commençant par un non-chiffre et ne contenant aucune séquence de plus de quatre chiffres.
Etant donné que le texte situé immédiatement à droite de la lettre centrale \d{4}
(ou [0-9]{4}
) doit être vide ou commencer par un non-chiffre, cela empêche la centrale \d{4}
de faire correspondre quatre chiffres comportant un autre (cinquième) chiffre juste à droite d'eux.
Cela garantit qu'une séquence de quatre chiffres est présente quelque part et qu'aucune séquence de cinq chiffres ou plus n'est présente nulle part.
Ce n'est ni mauvais ni mauvais de le faire de cette façon. Mais peut-être que la raison la plus importante d’envisager cette alternative est qu’elle clarifie l’avantage de l’utilisation (ou similaire) à la place, comme suggéré ci-dessus et dans la réponse de matt .grep -P '\d{4}' file | grep -Pv '\d{5}'
De cette façon, il est clair que votre objectif est de sélectionner des lignes contenant une chose mais pas une autre. De plus, la syntaxe est plus simple (elle peut donc être comprise plus rapidement par de nombreux lecteurs / responsables).
1234a12345
être affichée ou non?