Grep pour une ligne contenant seulement 5 ou 6 numéros

Comment voulez-vous grep pour une ligne contenant seulement 5 ou 6 numéros? Quelque chose comme ça.

cas 1 (a un espace de tête)

10 2 12 1 13 

cas 2 (pas d'espace de tête)

  1 2 3 4 5 6 

Je pensais que quelque chose comme ça fonctionnerait.

 grep -E '[0-9]{5}' 

grep -E '[0-9]{5}' cherche des nombres avec au less 5 numbers. Ce dont vous avez besoin est de 5 numbers avec au less un chiffre:

 grep -E '[0-9]+([^0-9]+[0-9]+){4}' 
  • [0-9]+ – un nombre d'au less un chiffre
  • [^0-9]+[0-9]+ – un chiffre comportant au less un chiffre, précédé d'au less un caractère non numérique. Nous répétons ensuite ceci 4 fois pour get 5 nombres séparés par des non-numbers.
  • Si l'exigence est exactement 5, vous pourriez vouloir entourer cette regex avec [^0-9] afin que toute la ligne soit appariée (avec les ancres, bien sûr).
  • En fonction de ce que vous voulez ici (est-ce que 1,2,3,4,6 qualifiés?), Vous pourriez regarder d'autres séparateurs. Par exemple, un nombre réel de notation scientifique ressemblera à: [+-]?(([0-9]+(\.[0-9]+)?)|([0-9]?\.[0-9]+))([eE][+-][0-9]+)? Donc, les séparateurs ne peuvent pas inclure . , e , etc. Ils ne peuvent être que des espaces, comme les notes mikeserv . Ou peut-être des virgules, s'il s'agit d'un logging CSV. Ou en fonction des parameters régionaux, une virgule serait le séparateur décimal. Variez [^0-9] selon votre besoin.

J'irais avec quelque chose d'un peu plus puissant que grep . Cela peut le faire dans perl:

 perl -ne 'print if s/\d+/$&/g == 5' your_file 

La substitution regex remplace tous les groupes d'un ou plusieurs numbers ( \d+ ) par eux-mêmes ( $& ): elle ne fait rien. Il est utilisé simplement pour un effet secondaire puisque l'opérateur s/// renvoie le nombre de fois où il a réussi à se substituer à son regex. Ainsi, la ligne n'est imprimée que si s/// trouvé 5 groupes de numbers.

Un autre perl :

 $ perl -MList::Util=first -Tnle ' s/^\s+|\s+$//g; @e = split /\s+/; print if @e == 5 || @e == 6 and !first {/\D/} @e; ' file 10 2 12 1 13 

Explication

  • s/^\s+|\s+$//g couper la ligne.

  • @e = split /\s+/ divise la ligne en tableau @e .

  • Nous imprimerons la ligne si:

    • array @e contient 5 ou 6 éléments.
    • Et aucun de ses éléments ne contient de caractères non numériques ( \D correspond à des caractères non numériques).
 grep -E '^(\s*[0-9]+\s+){4,5}[0-9]+\s*$' 
 awk '{l=$0; n = gsub(/[0-9]+/, "", l)}; n == 5 || n == 6' 

(même principe que dans la réponse de Joseph )

Une façon awk qui est personnalisable pour différents nombres de champs.
Aussi les espaces blancs n'ont pas d'importance.

 awk 'NF~/^(5|6)$/{x=0;for(i=1;i<=NF;i++)x+=($i~/^[0-9]+$/)}x==NF' file 

Cela vérifie que le nombre de champs est de 5 ou 6, bien qu'un plus grand nombre de champs puisse être ajouté si vos exigences changent.

Ensuite, il établit un countur à 0

Ensuite, la boucle vérifie chaque champ est un nombre et si elle ajoute 1 au countur

Si le countur est égal au nombre de champs, il imprime la ligne.

Exemple

input

  1 2 3 4 5 6 2 3 4 5 6 3 4 5 6 blah 1 2 3 4 5 4 3324 4 53 6 

output

  1 2 3 4 5 6 2 3 4 5 6 4 3324 4 53 6 

Je sais que je n'ai pas résolu en utilisant sed ou awk ou l'une des commands shell , Cependant, tcl a bien fonctionné.

J'ai gardé le script simple et convivial. des éléments comme 4a abc etc seront pris en charge

order

 script.tcl file 

Scénario

 #!/usr/bin/tclsh if {$argv == ""} { puts "please enter the arguement" exit ; } set tar_fl [lindex $argv 0] if {![file exists $tar_fl]} { puts "$tar_fl doesnot exist" exit ; } set flptr [open $tar_fl r] while {[gets $flptr line] >=0 } { if {[llength $line] !=5} {continue ;} if {[llength $line ] == 5} { if {[lsearch -regexp $line {[^0-9]}]> -1} {continue;} puts $line } } close $flptr 

Sortie

  10 2 12 1 13 1 2 3 4 5