2016-05-28 1 views
0

est-il un moyen de grep 2 occurrences d'un mot ou d'une instance d'un autre mot dans une seule ligne de cmd avec perl (perl est un must)greping deux choses différentes d'une commande de queue

Je suis en train de faire un fichier queue -f | grep -m 2 word_x OU grep word_y

J'essaie d'attraper word_x deux fois dans le fichier, si cela arrive, la queue s'arrête. Mais word_x n'apparaît pas toujours, donc j'aime avoir un autre word_y pour arrêter la commande tail.

si word_x apparaît 2 fois ou plus annuler la queue;
si word_x apparaît seulement 1 fois, recherchez une occurrence de word_y et annulez la queue;
si word_x n'apparaît pas mais que le mot y semble annuler la queue;

Word_y est le dernier mot qui apparaîtra toujours sur mon fichier.

Il peut donc être comme ces 3 exemples

texte
texte
word_x texte word_x
Test
word_y

texte
texte
texte word_x
Test
word_y

texte
texte
texte
word_y

je dois la queue du fichier. Je peux utiliser d'autres commandes, il n'a pas besoin d'être grep.

Est-ce possible? J'ai essayé plusieurs choses mais ne peux pas venir avec une solution simple, peut-être ce n'est pas possible de le faire sur une instruction de ligne de commande unique.

+1

[edit] votre question pour inclure quelques lignes d'entrée d'échantillon concis et testable et la sortie attendue. Si vous voulez dire 'tail -f' au lieu de' tail', alors assurez-vous de le préciser - c'est une distinction très importante. –

+0

Aussi, voulez-vous des mots entiers. (par exemple si 'abc' était un mot,' abcd xyz' peut être une correspondance ou seulement 'abc xyz'). Plus vous spécifiez ceci, meilleurs seront les résultats –

+1

Je ne peux pas voir ce que cela a à voir avec Perl? –

Répondre

0

Sans entrée échantillon/sortie, il est une supposition, mais il semble que c'est ce que vous cherchez:

tail file | awk '{x+=gsub(/word_x/,"&")} x==2||/word_y/{exit} 1' 

En fonction des besoins que vous ne l'avez pas encore partagé avec nous, vous devrez peut-être des limites de mots aussi, par exemple avec GNU awk:

tail file | awk '{x+=gsub(/\<word_x\>/,"&")} x==2||/\<word_y\>/{exit} 1' 

Si vous voulez seulement examiner les cas où word_x se produit deux fois sur une ligne alors il est bref:

tail file | awk 'gsub(/\<word_x\>/,"&")==2||/\<word_y\>/{exit} 1' 
+1

Cela semble être ce que je cherchais, merci, je vais essayer dès que je reviens à ma machine de développement –

+0

D'après le montage d'Allan, il semble que les fréquences des mots doivent être sur une base par ligne. Ainsi, pour une séquence 'word1 able',' word1 baker', 'word2 charlie', votre commande avorte sur boulanger au lieu de charlie. Allan, pouvez-vous confirmer/clarifier cela? –

+0

@CraigEstey merci pour les heads up J'ai effectivement lu l'échantillon différemment et il y avait un bug dans mon script où je comptais le nombre de lignes qui contiennent word1 au lieu du nombre d'occurrences de word1 et donc quand word1 s'est produit deux fois sur une ligne Je ne comptais qu'une seule fois. Je l'ai réparé maintenant. –

0

(1) si word_x apparaît 2 fois ou plus annuler la queue

C'est clair.Mais, ce qui suit est incompatible

(2) si word_x apparaît seulement 1 fois, chercher word_y

Cela dit chercher word_y que si la ligne a une seule occurrence de word_x

(3) et abandonner la queue si doesnt word_x apparaît mais le mot y apparaît abandonner la queue

Cependant, cela dit que pour regarder word_y si word_x ne pas apparaît.

(2) et (3) semblent conflit. Pour moi, ignorer (2) et utiliser (3) est le plus logique.

En outre, vous ne dites pas que vous vouliez la ligne « abort » à transmettre ou non.

est ici un code que je crois fonctionnera. J'ai fait un peu de test dessus

#!/usr/bin/perl 

my($word_x) = shift(@ARGV); 
my($word_y) = shift(@ARGV); 

# quirk of perl -- the regex needs the longest to be first in order if had 
# similar words like "abc" and "abcd" 
my(@rgx) = ($word_x,$word_y); 
@rgx = sort({length($b) <=> length($a)} @rgx); 
my($rgx) = join("|",@rgx); 

while (my $buf = <STDIN>) { 
    chomp($buf); 

    # NOTE: this assumes the "abort" line should be printed 
    print($buf,"\n"); 

    # get frequency of each word 
    # NOTE: this grabs partials, so it may need \b or \W wrappers 
    my(%freq); 
    while ($buf =~ /($rgx)/go) { 
     $freq{$1} += 1; 
    } 

    my $xcnt = $freq{$word_x}; 

    # got two or more of x -- we're done 
    last if ($xcnt >= 2); 

    # only look for y if x does _not_ appear at all 
    if ($xcnt == 0) { 
     # found a y -- we're done 
     last if ($freq{$word_y} >= 1); 
    } 

    # NOTE: this assumes the "abort" line should _not_ be printed 
    # use either of the prints but _not_ both 
    ###print($buf,"\n"); 
} 
+0

Merci pour la réponse, mal essayer quelque chose comme ce code merci. BTW J'ai édité le post original, ce que je cherche à faire est un appel de ligne de cmd simple, je me demande est que c'est possible sans faire un nouveau script. –

+0

Merci pour l'édition.Pour clarifier, votre nouvelle règle (2) implique que 'text x text y y' ne doit pas correspondre parce qu'il a _one_' x' et a besoin de _one_ 'y' alors que cette ligne a _two_' y's? Si ce n'est pas le cas, seulement (1) et (3) sont nécessaires comme (3) couvertures (2). Notez que mon script et Ed utilisent des hachages pour le mot freq, donc quelque chose de plus simple pourrait ne pas être possible. Avec perl, il peut invoquer 'tail -f' dans un tube en interne, donc' script word_x word_y [ifile] 'et _no_ shell shell pour' tail -f file | script' nécessaire. On dirait que vous ne voulez que des mots entiers pour correspondre? Si oui, mon regex est faux et le script peut être simplifié –