Grep supprime la ligne avec 0 mais pas 0,2?


12

J'ai un fichier dont le contenu est similaire au suivant.

0
0
0.2
0
0
0
0

Je dois supprimer toutes les lignes avec un seul zéro.
Je pensais utiliser grep -v "0", mais cela supprime également la ligne contenant 0,2. J'ai vu que je pouvais utiliser l' -woption, mais cela ne semble pas fonctionner non plus.

Comment supprimer toutes les lignes contenant un seul 0 et conserver toutes ces lignes commençant par un 0?



1
@JulienLopez Ce n'est pas une dupe de cette question. Cette question concerne la correspondance d'un mot, et a répondu par -w, qui échoue ici.
Sparhawk

Pourquoi êtes-vous obligé d'utiliser greppour cette tâche? Et qu'entendez-vous exactement par un seul zéro ? Cela ressemble beaucoup à un problème XY .
Roland Illig

1
@RolandIllig c'était 1 heure avant le coucher et je voulais commencer à traiter une série de 500 000 chaînes pour vérifier s'il s'agissait de clés privées bitcoin et si oui, trouver l'équilibre. La prochaine fois que j'ai eu le temps de le regarder, j'avais traité plusieurs milliers de chaînes et je voulais juste analyser toutes les valeurs non nulles.
Philip Kirkbride

Réponses:


35
grep -vx 0

De man grep:

-x, --line-regexp
       Select only those matches that exactly match the whole line.
       For a regular expression pattern, this is like parenthesizing
       the pattern and then surrounding it with ^ and $.

-wéchoue car le premier 0dans 0.02est considéré comme un "mot", et donc cette ligne est mise en correspondance. En effet, il est suivi d'un caractère "non-mot". Vous pouvez le voir si vous exécutez la commande d'origine sans -v, c'est-à-dire grep -w "0".


Vous pouvez également utiliser l' -Foption car nous n'utilisons pas de modèles d'
expression régulière

@glennjackman J'ai peut-être lu ceci plus tôt, mais je n'arrive pas à le trouver maintenant. Courir avec -F(étonnamment pour moi) semble prendre un temps similaire, voire légèrement plus lent (~ 5 à 10%). Par conséquent, je ne sais pas quel serait l'avantage.
Sparhawk

2
Il est possible que le moteur RegEx soit utilisé si souvent et si largement utilisé qu'ils en ont implémenté une version très efficace, mais qu'une "recherche simple" n'a probablement pas été mise à niveau depuis 30 ans.
Nelson

@Sparhawk: a grepprobablement un cas spécial pour les expressions rationnelles sans métacaractères, car c'est un cas d'utilisation courant. Il est surprenant que fgrepce soit plus lent, mais il n'est pas surprenant que la surcharge de remarquer ce cas spécial lors de la compilation d'un modèle court soit négligeable par rapport au temps nécessaire pour analyser un gros fichier. (Si cela nécessite un cas spécial pour aller aussi vite, contre un modèle avec une classe de personnage ou x.*y.)
Peter Cordes

Mais c'est peut-être une simplification excessive car l'entrée est en fait de nombreuses lignes courtes (pas une chaîne géante). J'oublie si grepreconnaît tout caractère autre que la \nnouvelle ligne comme séparateur de ligne. Sinon, l'implicite ^et $ peut toujours se transformer en une recherche de chaîne fixe comme strstr(big_buf, "\n0\n"). (Ou 0\nau début d'un tampon.) Mais nous ne cherchons pas seulement la première correspondance potentiellement loin dans un grand tampon, nous voulons filtrer efficacement. Mais de toute façon, en théorie oui, c'est juste un memcmp à 2 octets au début de chaque ligne, et vous espérez que fgrep et grep le verront.
Peter Cordes

28

Avec grep:

grep -v "^0$" file

^signifie le début de la ligne, $signifie la fin de la ligne.


2
C'est ce que l'utilisateur a demandé: évitez les lignes contenant seulement 1 "0".
Olivier Dulac

1
Je ne mettrais pas de signe littéral en dollars entre guillemets doubles comme ça.
user541686

@mehrdad ce n'est pas un gros problème avec l'expression régulière car c'est généralement le dernier caractère ou le suivant ne sera pas[a-Z0-9]
Sampo Sarrala - codidact.org

14

Bien que cela grep puisse être utilisé pour cela (comme d'autres réponses le montrent clairement), prenons un peu de recul et réfléchissons à ce que vous voulez réellement:

  • Vous avez un fichier contenant des nombres
  • Vous souhaitez effectuer un filtrage basé sur la valeur numérique .

Regex interprète les données de séquence de caractères. Ils ne connaissent pas les chiffres, seulement les chiffres individuels (et leurs combinaisons régulières). Bien que dans votre cas particulier, il existe un simple hack autour de cette limitation, il s'agit en fin de compte d'une incompatibilité des exigences.

À moins qu'il n'y ait une très bonne raison d'utiliser grepici (par exemple parce que vous l'avez mesuré, et qu'il est beaucoup plus efficace et que l'efficacité est cruciale dans votre cas), je recommande d'utiliser un outil différent.

awk, par exemple, peut filtrer sur la base de comparaisons numériques, par exemple:

awk '$1 == 0' your_file

Mais aussi, pour obtenir toutes les lignes contenant des nombres supérieurs à zéro:

awk '$1 > 0' your_file

J'adore les regex, c'est un excellent outil. Mais ce n'est pas le seul outil. Comme dit le proverbe, si tout ce que vous avez est grep, tout ressemble à une langue normale.


3
Je suis entièrement d'accord pour dire que awk peut être plus élégant ici ... cependant, il correspondra peut-être un peu plus que ce que l'utilisateur attend (chaque valeur numérique évaluant à 0). -À- dire, printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'correspondra à : 0, 0.0et -0.0... et aussi 0 also! Pas seulement "0". (ce qui est parfois nécessaire, parfois non). Si l'utilisateur ne veut que "0": awk '/^0$/' (ou grep '^0$'). Vous devez également modifier: l'utilisateur doit ajouter !pour annuler le test, afin qu'il masque 0(et les autres zéros) et affiche le reste. Soit:awk '!( $0 == 0)'
Olivier Dulac le

1
@Olivier, ou vérifiez la valeur de la chaîne:$1 == "0"
glenn jackman

1
@OlivierDulac J'ai explicitement utilisé >plutôt que !=(ou, de manière équivalente ! (… == …)) pour souligner qu'il s'agit d'une comparaison numérique arbitraire, pas seulement de l'égalité. Quant à votre autre commentaire, cela est tout à fait vrai, mais nous sommes essentiellement de retour dans le territoire de comparaison de chaînes et la solution existante utilisant des grepœuvres (bien awksûr, elle fonctionne également).
Konrad Rudolph

@KonradRudolph fair points :)
Olivier Dulac

1
@glennjackman: belle astuce en effet. Mais alors OP préfère faire des tests$0=="0"
Olivier Dulac

5

grep's -west un peu alambiqué de manière à diviser la chaîne d'origine en constituants mots et non-mots (tout sauf les lettres, les chiffres ou le trait de soulignement). Comme il a déjà rencontré aa constituant mot valable 0en 0.02avait affirmé la logique de négation de supprimer la ligne.

L'utilisation sedest un peu facile dans ce contexte pour supprimer simplement les mots entiers qui correspondent

sed '/^0$/d' file

3

Lorsque les lignes que vous souhaitez supprimer contiennent uniquement un 0 suivi de la ligne suivante, vous pouvez sélectionner ces lignes en exécutant la commande suivante:

grep -v "^0$"

Cela n'imprimera que les occurrences 0qui se trouvent à la fin d'une ligne et au début d'une ligne en même temps. L' -voption inverse alors notre sélection.


1
Cette réponse est presque identique à celle d'Arkadiusz Drabczyk, mais vous l'avez oublié -v, donc cela ne fonctionne pas.
Sparhawk

Vous avez raison. Je tapais pendant qu'il postait sa réponse, donc je n'ai pas vu qu'elle avait déjà été donnée. J'ai mal lu cette partie avec l' -voption, merci!
majesticLSD

0
  • \ b - bordure de mot

grep -v "\b0\b"

  • faire correspondre le début de la ligne, votre motif et la fin de la ligne

grep -v "^0$"

  • ou comme @Sparhawk l'a suggéré -vx lineregexp

-w fonctionne, mais dans votre cas, 0,2 sont deux mots car le caractère point est un séparateur de mots.


grep -v "\b0\b"ne fonctionne pas vraiment ici. Quelle version de grep utilisez-vous?
Arkadiusz Drabczyk

fonctionne avec grep (BSD grep) 2.5.1-FreeBSDsur macOS et grep (GNU grep) 2.16sur ubuntu
Jakub Jindra

1
Utilisation de l'expression rationnelle GNU \<et \>comme limites de mots, mais cela aura le même effet que-w
glenn jackman

0

Une autre réponse par souci de variété, en supposant que vous avez un PCRE-activé grep

grep -Pv "^0(?!\.)"

cela effectue une anticipation négative pour faire correspondre les lignes qui commencent par 0et ne sont pas suivies d'un point. -vRejette ensuite les lignes qui ne correspondent pas. Vous pouvez voir en action ici


1
Cela supprimera également les lignes telles que 0123, ce qui n'est pas ce que le PO souhaite
iruvar

0

En supposant que toute ligne qui n'est pas un simple 0 a un point

grep '\.' file

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.