J'apprends Linux et j'ai un défi que je n'arrive pas à résoudre seul. C'est ici:
grep une ligne d'un fichier qui contient 4 nombres dans une ligne mais pas plus de 4.
Je ne sais pas comment aborder cela. Je peux rechercher des nombres spécifiques mais pas leur montant dans une chaîne.
command-line
grep
text-processing
Bouddha
la source
la source
1234a12345
être affichée ou non?\b\d{4}\b
Réponses:
Il y a deux façons d'interpréter cette question. Je vais aborder les deux cas. Vous voudrez peut-être afficher des lignes:
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:
Cela utilise des expressions régulières Perl , que Ubuntu
grep
( GNU grep ) prend en charge via-P
. Il ne correspond pas à texte comme12345
, ni ne correspond au1234
ou2345
qui font partie de celui - ci. Mais elle correspondra1234
à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}
correspondx
4 fois. (La{
}
syntaxe n'est pas spécifique aux expressions rationnelles Perl; elle s'appliquegrep -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).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 pargrep
(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
:Manière alternative, sans assertions de Look-Behind and Look-Ahead
Cependant, si vous:
grep
ne prend pas en charge-P
ou ne souhaite pas utiliser une expression régulière Perl, et... vous pouvez y parvenir avec une expression régulière étendue :
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 de0
travers9
. 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:(^|[^0-9])
), et($|[^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]
: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:Manière alternative, avec un motif simple
Si vous préférez vraiment une
grep
commande quigrep
s séparés par un tuyau , comme ci-dessus)... alors vous pouvez utiliser:
L'
-x
indicateur fait engrep
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 lesquelsgrep
ne prend pas en charge-P
, vous pouvez les remplacer par[0-9]
et[^0-9]
(ou avec[[:digit:]]
et[^[:digit]]
):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).
la source
Cela vous montrera 4 chiffres à la suite mais pas plus
Notez le ^ signifie pas
Il y a un problème avec ceci bien que je ne sois pas sûr de comment le réparer ... si le nombre est la fin de la ligne, alors il ne s'affichera pas.
Cette version plus laide cependant fonctionnerait pour ce cas
la source
a12345b
, car il correspond2345b
.Si
grep
ne supporte pas les expressions régulières perl (-P
), utilisez la commande shell suivante:où
printf '[0-9]%.0s' {1..4}
va produire 4 fois[0-9]
. Cette méthode est utile lorsque vous avez de longs chiffres et que vous ne voulez pas répéter le motif (remplacez-le simplement4
par votre nombre de chiffres à rechercher).Utilisation
-w
cherchera les mots entiers. Toutefois, si vous êtes intéressé par les chaînes alphanumériques, telles que1234a
, ajoutez[^0-9]
à la fin du motif, par exempleL'utilisation
$()
est fondamentalement une substitution de commande . Consultez ce post pour voir comment seprintf
répète le motif.la source
Vous pouvez essayer la commande ci-dessous en remplaçant
file
par le nom de fichier actuel dans votre système:Vous pouvez également consulter ce tutoriel pour plus d'utilisations de la commande grep.
la source