Comment trouver des fichiers contenant deux chaînes ensemble sous Linux?

11

Je veux trouver des fichiers contenant deux chaînes ensemble, par exemple le fichier contient à la fois string1et string2.

Je veux le chemin complet des fichiers en sortie. Je ne veux pas voir les avertissements "autorisation refusée".

alwbtc
la source

Réponses:

15
grep -l string2 `grep -l string1 /path/*`

ce qui est le même que

grep -l string2 $(grep -l string1 /path/*)

Edit: voici pourquoi grep string1 /path/* | grep string2ne fait pas ce que je pense qu'alwbtc veut.

$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$

Rien trouvé, mais le fichier b contient les deux chaînes.

Voici ce que je pense que alwbtc veut

$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
RedGrittyBrick
la source
1
Il s'agit d'une solution soignée et plus utile que la mienne. Pour ceux qui veulent savoir ce qui se passe ici (il m'a fallu un peu de temps pour comprendre), il utilise l' -loption pour renvoyer les noms de fichiers au lieu des lignes. Il utilise ensuite le signe dollar ou les guillemets pour passer cette liste comme FILEargument dans le deuxième grep. Cela permet au deuxième grep de rechercher l'intégralité de chaque fichier trouvé au lieu des lignes individuelles comme dans ma solution.
embedded.kyle
Vous avez manqué une -loption pour que les deux commandes soient considérées comme égales.
pong
2

Connectez-vous les uns grepaux autres:

grep "string1" /path/to/files/* | grep "string2"

embedded.kyle
la source
5
Si les deux chaînes sont sur des lignes différentes dans le fichier, cela ne fonctionnera pas.
RedGrittyBrick
1
Je ne savais pas qu'il fallait qu'ils soient sur la même ligne @RedGrittyBrick
slhck
@slhck: J'ai mis à jour ma réponse pour montrer ce que je pense qu'alwbtc veut et pourquoi cette réponse ne fait pas ça. Bien sûr, j'ai peut-être mal compris ce que veut alwbtc et embedded.kyle a peut-être bien compris - je ne pense pas cependant.
RedGrittyBrick
1

Voici la commande équivalente à la réponse de RedGrittyBrick :

ack string2 $(ack string1 -l)

Fonctionne de la même manière (sauf ackpar défaut recherche récursivement le répertoire courant). Le contenu dans les $()recherches string1mais -lne génère que les noms de fichiers où cette chaîne a été trouvée. Ils sont ensuite passés en tant qu'arguments dans la commande externe, ce qui signifie que la string2recherche s'effectue uniquement dans cette liste de fichiers.

congusbongus
la source
0
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)

ou moins redondant:

search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)

Cela fonctionnera si les chaînes se trouvent sur des lignes différentes du même fichier et évitera également les faux positifs si un nom de fichier contient l'une des chaînes.

user381521
la source
0

Pour élaborer sur la solution de @ RedGrittyBrick qui présente un inconvénient lors de l'exécution de la commande sans assistance plus pour supprimer la sortie d'erreur comme prévu et pour rechercher des fichiers de manière récursive, vous pourriez envisager

grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)

-sL'option supprimera les messages d'erreur L'
-roption permet de rechercher des chaînes dans des répertoires imbriqués arbitrairement
!combinés avec des && echo /dev/nullgaranties que la commande ne raccroche pas. Sinon, si le inner grepne trouve aucun fichier, il ne sortira rien, de sorte que l' outer grepattendra indéfiniment pour la recherche. Cette solution de sorties /dev/nulldans ces cas afin outer greprechercheront STRING1dans /dev/nulloù il est censé ne pas trouver quoi que ce soit.

pong
la source
0

Je cherchais un moyen extensible de faire 2 cordes ou plus et j'ai trouvé ceci:

grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3

Le premier grep trouve récursivement les noms des fichiers contenant string1dedans path-to-files.

Les résultats sont canalisés dans xargslesquels s'exécute une ou plusieurs commandes grep sur ces fichiers pour string2.

Les résultats sont ensuite canalisés dans une autre xargscommande pour string3- c'est la même chose que le premier xargsappel, mais en recherchant une chaîne différente.

L'utilisation de xargsévitera les problèmes où il y a tellement de résultats que la ligne de commande résultante de l'utilisation des back-ticks est trop longue.

Pour éviter les avertissements, nous pouvons rediriger stderrvers /dev/null:

grep -rl string1 path-to-files  2>/dev/null | xargs grep -l string2

Il n'est pas nécessaire lors des appels grep suivants, car il string1a déjà été trouvé dans le fichier, les autorisations sont donc réputées bonnes.

awatts
la source