web-dev-qa-db-fra.com

Comment grep pour deux mots existant sur la même ligne?

Comment puis-je grep pour les lignes qui contiennent deux mots d'entrée sur la ligne? Je cherche des lignes qui contiennent les deux mots, comment puis-je le faire? J'ai essayé la pipe comme ça:

grep -c "Word1" | grep -r "Word2" logs

Il se bloque juste après la première commande de pipe.

Pourquoi?

103
user157195

Pourquoi passez-vous -c? Cela montrera simplement le nombre de matchs. De même, il n'y a aucune raison d'utiliser -r. Je vous suggère de lire man grep.

Pour grep pour 2 mots existant sur la même ligne, il suffit de faire:

grep "Word1" FILE | grep "Word2"

grep "Word1" FILE imprimera toutes les lignes contenant Word1 à partir de FILE, puis grep "Word2" imprimera les lignes contenant Word2. Par conséquent, si vous les combinez à l'aide d'un tuyau, des lignes contenant Word1 et Word2 s'afficheront.

Si vous voulez juste compter le nombre de lignes contenant les 2 mots sur la même ligne, faites:

grep "Word1" FILE | grep -c "Word2"

Aussi, pour répondre à votre question, pourquoi est-il bloqué: dans grep -c "Word1", vous n'avez pas spécifié de fichier. Par conséquent, grep attend une entrée de stdin, raison pour laquelle il semble se bloquer. Vous pouvez appuyer sur Ctrl+D pour envoyer un EOF (fin de fichier) afin qu'il se ferme.

147
houbysoft

Ordonnance

Une réécriture simple de la commande dans la question est la suivante:

grep "Word1" logs | grep "Word2"

Le premier grep recherche les lignes avec 'Word1' dans le fichier 'logs', puis les insère dans le second grep qui recherche les lignes contenant 'Word2'.

Cependant, il n'est pas nécessaire d'utiliser deux commandes comme ça. Vous pouvez utiliser étendu grep (grep -E ou egrep):

grep -E 'Word1.*Word2|Word2.*Word1' logs

Si vous savez que 'Word1' précédera le mot 'Word2' sur la ligne, vous n'avez même pas besoin des alternatives et des fonctions normales grep suffiraient:

grep 'Word1.*Word2' logs

Les variantes "une commande" présentent l'avantage de ne comporter qu'un seul processus en cours d'exécution. Par conséquent, les lignes contenant "Word1" ne doivent pas nécessairement être transmises via un canal au processus secondaire. Cela dépend de la taille du fichier de données et du nombre de lignes correspondant à "Word1". Si le fichier est petit, les performances risquent de ne pas être un problème et l'exécution de deux commandes convient. Si le fichier est volumineux mais que quelques lignes contiennent "Word1", peu de données seront transmises sur le canal et l'utilisation de deux commandes est acceptable. Toutefois, si le fichier est volumineux et que 'Word1' apparaît fréquemment, vous risquez alors de transmettre des données significatives en aval, où une seule commande évite cette surcharge. Contre cela, la regex est plus complexe; vous devrez peut-être effectuer une analyse comparative pour déterminer ce qui convient le mieux, mais uniquement si la performance compte vraiment. Si vous exécutez deux commandes, essayez de sélectionner le mot le moins fréquent dans la première grep afin de minimiser la quantité de données traitées par la seconde.

Diagnostic

Le script initial est:

grep -c "Word1" | grep -r "Word2" logs

C'est une séquence de commande étrange. La première grep va compter le nombre d'occurrences de 'Word1' sur son entrée standard et l'imprimer sur sa sortie standard. Jusqu'à ce que vous indiquiez EOF (par exemple en tapant Control-D), il restera assis à attendre que vous tapiez quelque chose. Le second grep effectue une recherche récursive sur 'Word2' dans les fichiers situés sous le répertoire logs (ou, s'il s'agit d'un fichier, dans le fichier logs). Ou, dans mon cas, cela échouera car il n'y a ni fichier ni répertoire nommé logs où je suis en train d'exécuter le pipeline. Notez que la seconde grep ne lit pas du tout son entrée standard, le tuyau est donc superflu.

Avec Bash, le shell parent attend la fin de tous les processus du pipeline. Il attend donc que le grep -c se termine, ce qui ne se fera pas tant que vous n’indiquerez pas EOF. Par conséquent, votre code semble rester bloqué. Avec Heirloom Shell , la seconde grep se termine et se termine, et le shell invite à nouveau. Maintenant, vous avez deux processus en cours d'exécution, le premier grep et le shell. Ils tentent tous deux de lire à partir du clavier. Il n'est pas possible de déterminer laquelle obtiendra une ligne d'entrée donnée (ni un EOF indication).

Notez que même si vous saisissiez des données en entrée dans le premier grep, vous n'obtiendrez que les lignes contenant "Word2" affichées dans la sortie.


Note de bas de page:

À un moment donné, la réponse utilisée:

grep -E 'Word1.*Word2|Word2.*Word1' "$@"
grep 'Word1.*Word2' "$@"

Cela a déclenché les commentaires ci-dessous.

61
Jonathan Leffler

vous pourriez utiliser awk. comme ça...

cat <yourFile> | awk '/Word1/ && /Word2/'

L'ordre n'est pas important. Donc, si vous avez un fichier et ...

un fichier nommé, fichier1 contient:

Word1 is in this file as well as Word2
Word2 is in this file as well as Word1
Word4 is in this file as well as Word1
Word5 is in this file as well as Word2

ensuite,

/tmp$ cat file1| awk '/Word1/ && /Word2/'

aura pour résultat,

Word1 is in this file as well as Word2
Word2 is in this file as well as Word1

oui, awk est plus lent.

8

Le problème principal est que vous n’avez fourni aucune entrée au premier grep. Vous aurez besoin de réorganiser votre commande quelque chose comme

grep "Word1" logs | grep "Word2"

Si vous voulez compter les occurrences, mettez un '-c' sur le second grep.

7
sysboy

Vous chat essayez avec la commande ci-dessous

cat log|grep -e Word1 -e Word2
5
user2724604

grep Word1 file_name | grep Word2

cela semble être le moyen le plus facile pour moi

2
user4813867

Utilisez grep:

grep -wE "string1|String2|...." file_name

Ou vous pouvez utiliser:

echo string | grep -wE "string1|String2|...."
0
HARSH