8 votes

Comment grep une section d'un fichier en bash Shell

Comment puis-je "grep" les lignes entre une occurrence d'une chaîne1 et la (Nième) occurrence d'une chaîne2.

par exemple

si le fichier a une ligne :

A
B
C
D
E

F
G
B
C
E

Q

Je veux obtenir les lignes en gras (celles qui commencent par un B et finissent par un E).

Peut-on le faire en utilisant grep ? ou un autre outil de ligne de commande Unix ?

12voto

galeksic Points 121

grep n'est pas bien adapté à cette tâche, vous devez passer à un outil supérieur :

sed -n '/^B/,/^E/p' infile

Sortie :

B
C
D
E
B
C
E

En ce qui concerne la Nième exigence, je pense que le plus simple est d'avancer encore une fois un outil "vers le haut", à savoir awk :

awk '/^B/ { f = 1; n++ } f && n == wanted; /^E/ { f = 0 }' wanted=2 infile

Sortie :

B
C
E

Le drapeau f sera défini lorsque /^B/ est rencontrée et est désactivée lorsque /^E/ se produit, de la même manière que la notation des sédiments fonctionne. n tient un compte du nombre de blocs passés et de la date à laquelle ils sont passés. f == 1 && n == wanted est vrai, le bloc par défaut sera exécuté ( { print $0 } ).

3voto

mpy Points 24817

@Thor's sed ne peut pas être battu, mais avec la commande suivante perl script J'essaie de répondre à la partie de votre question entre parenthèses : " ... la (Nième) occurrence ... ".

Utilisation :

./script <start-regex> <end-regex> [N]

Exemples avec le fichier de votre question :

$ ./script "B" "E" < examplefile
B
C
D
E
B
C
E

$ ./script "B" "E" 2 < examplefile
B
C
D
E
F
G
B
C
E

Il n'y a pas de vérification d'erreur ou quoi que ce soit et le script n'est pas gourmand, c'est-à-dire que de A B C D E E F uniquement B C D E seront grep'ed avec N=1.


#!/usr/bin/perl

if ($ARGV[2] != "") { $n = $ARGV[2] } else { $n = 1 }
$begin_str = $ARGV[0];
$end_str = $ARGV[1];

while(<STDIN>) {
  if($_ =~ $begin_str) { $flag=1 }             # beginning of match, set flag    
  if($_ =~ $end_str && $flag eq 1) { $i++ }    # i-th occurence of end string

  if($i eq $n) {                               # end of match after n occurences of end string
    $flag=2;
    $i=0; 
  }

  if ($flag ge 1) {                            # append currrent line to matching part
    $out.=$_;
  }

  if($flag eq 2) {                             # after detection of end of match, print complete match
    print $out;
    # print "---\n";                           # separator after a match
    $out="";
    $flag=0;
  }

}

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X