Commentaires
Réponse
GNU grep
Devrait être un peu plus rapide car le second grep
peut opérer sur une liste de fichiers.
grep -lZ "foo" * | xargs -0 grep -l "321"
POSIX grep avec find
find
est plus utile si vous souhaitez rechercher des répertoires récursifs (dans ce cas, perdez -mindepth
et -maxdepth
options.
find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} +
Commentaires
-
-r
a bien fonctionné sur le premiergrep
pour rendre cette solution GNU récursive pour moi, au lieu dutiliser la ligne POSIX avec tous cesexec
s
Answer
Vous pouvez le faire avec un court script:
for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done
Vous pouvez également le faire sur une seule ligne:
for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done
grep
renvoie 0 (true) sil a trouvé la chaîne et le &&
séparant les commandes signifie que le second ne fonctionnera que si le premier était vrai. Loption -q
garantit que grep
naffiche rien.
Lécho ne sexécutera que si les deux chaînes étaient trouvé dans le même fichier.
Jai pensé à une manière différente de le faire. Cette méthode sera probablement plus efficace si les fichiers en question sont plus volumineux que votre RAM installée car il suffit de grep
à travers chaque fichier une fois.
for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done
et la version sur une ligne:
for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done
Commentaires
- Pour votre solution plus efficace: que se passe-t-il si le fichier contient " foo foo "?
- Cela ' est à quoi sert
uniq | sort | uniq
. " foo foo " finit par être une ligne mais " foo 321 " finit par être deux lignes cargrep -o
renvoie toutes les chaînes trouvées sur des lignes séparées, même si elles ont commencé sur la même ligne. - Si les fichiers deviennent si volumineux quil serait acceptable de bifurquer au moins six fois par fichier, il est probablement logique dutiliser awk à la place afin que les fichiers naient pas besoin dêtre recherchés jusquà la fin.
- @Ladadadada a obtenu il. 🙂
- @HaukeLaging
grep -q
etgrep -l
ne recherche pas jusquà la fin du fichier: ils sortent aussitôt comme une correspondance est trouvée. Je me demande pourquoi la première solution nest pas ' tfor FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done
Réponse
Étrange. Pour moi, les deux variantes fonctionnent (grep (GNU grep) 2.13):
grep "foo\|321" grep -E "foo|321"
Edit 1 – afficher les fichiers avec les deux correspondances uniquement
La réponse for file in *
fonctionne mais peut devenir un cauchemar de performances (pour de grandes quantités de fichiers ): au moins deux processus par fichier. Cest plus rapide (dans le monde GNU):
find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2
string1 devrait être celui qui donne le moins de correspondances.
Commentaires
- Le demandeur recherche le résultat à renvoyer vrai uniquement si un fichier contient les deux chaînes plutôt que sil ne correspond quà au moins une.
- Jaime ça Option
--files-with-matches
. Lisez-le simplement dans la page de manuel et cela provoque larrêt de grep après avoir trouvé la première correspondance, ce qui signifie quil est ' très efficace pour les gros fichiers si la correspondance se produit tôt. Il indique également que loption courte-l
est spécifiée par POSIX, elle peut donc être utilisée en dehors du monde GNU. - @Ladadadada Lefficacité nest pas un avantage sur votre -q, cependant. En mentionnant GNU, je ne pensais pas ' à –files-with-matches mais à -0 / –null.Ce qui me vient à lesprit: lexpansion des chemins contient un tri alphabétique (vraiment mauvais: il semble que ' t même pas être désactivé) donc pour dénormes quantités de fichiers, même votre
for file in *
cesse vraiment dêtre amusant. - En effet, les optimisations defficacité seraient assez différentes pour quelques gros fichiers par rapport à beaucoup de petits et
*
juste ' ne fonctionnera pas du tout après quelques milliers de fichiers. - @Ladadadada Cela ne ' t fonctionne dans le cadre dune ligne de commande pour une commande externe:
grep foo *
Maisfor file in *
est une structure interne au shell donc je suppose que la limite de ligne de commande nest pas applicable ici.
Réponse
En gros, pour trouver tous les fichiers, y compris un chaîne dans un répertoire, vous pouvez utiliser:
grep -lir "pattern" /path/to/the/dir
-
-l
: pour effectuer cette analyse sarrêtera sur la première correspondance -
-i
: pour ignorer les distinctions de casse dans le modèle et les fichiers dentrée -
-r
: recherchez tous les fichiers sous le répertoire, de manière récursive
Pour rechercher deux modèles, essayez ceci:
grep -lr "321" $(grep -lr "foo" /path/to/the/dir)
Commentaires
- Les commentaires ennuyeux standard sur
$()
ne gérant pas bien les espaces sappliquent. En pratique, pour une doublure au niveau du shell, cette commande fonctionnera correctement.
Réponse
Devrait être
grep -e "foo" -e "321" *
Utilisez -e pour plusieurs modèles
EDIT
Au cas où vous auriez besoin des deux pour correspondre:
grep -e ".*foo.*321.*" *
Si lordre na pas dimportance:
grep -e ".*foo.*321.*" ".*321.*foo.*" *
Commentaires
- Cela ne fournit pas de réponse à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son message.
- @mdpc Je pense que cela fournit une réponse. Quest-ce qui vous fait penser différemment?
- @HaukeLaging Parce quil renvoie si lun des motifs correspond. LOP recherche un cas où il ne renvoie vrai que si les deux sont trouvés dans le fichier.
- Daprès ce que je comprends, cela ne trouve que les fichiers où les deux chaînes contiennent sur la même ligne (je don ' t pense. correspond aux nouvelles lignes par défaut)
321
au lieu debar
: – D