Fichiers Grep contenant deux occurrences ou plus d'une chaîne spécifique
J'ai besoin de trouver des fichiers où une chaîne spécifique apparaît deux fois ou plus.
Par exemple, pour trois fichiers:
Fichier 1:
Hello World!
Fichier 2:
Hello World!
Hello !
Fichier 3:
Hello World!
Hello
Hello Again.
-
Je veux grep Hello
et ne récupérer que les fichiers 2
& 3
.
Et ça:
grep -o -c Hello * | awk -F: '{if ($2 > 1){print $1}}'
Étant donné que la question est étiquetée grep
, voici une solution utilisant uniquement cet utilitaire et bash
(aucune awk
requise):
#!/bin/bash
for file in *
do
if [ "$(grep -c "Hello" "${file}")" -gt 1 ]
then
echo "${file}"
fi
done
Peut être un one-liner:
for file in *; do if [ "$(grep -c "Hello" "${file}")" -gt 1 ]; then echo "${file}"; fi; done
Explication
- Vous pouvez modifier l’instruction
for file in *
avec l’extension de shell souhaitée pour obtenir tous les fichiers de données. grep -c
renvoie le nombre de lignes correspondant au modèle, avec plusieurs correspondances sur une ligne comptant toujours pour une seule ligne correspondante.if [ ... -gt 1 ]
vérifie que plusieurs lignes correspondent dans le fichier. Si c'est le cas:echo ${file}
affiche le nom du fichier.
Après avoir lu votre question, je pense que vous souhaitez également rechercher l’affaire hello hello
sur une ligne. (find files where a specific string appears twice or more.
) alors je viens avec ce one-liner:
awk -v p="hello" 'FNR==1{x=0}{x+=gsub(p,p);if(x>1){print FILENAME;nextfile}}' *
- dans la ligne ci-dessus,
p
est le motif que vous souhaitez rechercher - il imprimera le nom de fichier si le fichier contient le motif deux fois ou plus. peu importe qu'ils soient dans les mêmes lignes ou des lignes différentes
- pendant le traitement, après avoir vérifié une ligne, si nous avions déjà trouvé deux modèles ou plus, imprimons le nom de fichier et arrêtons le traitement du fichier actuel, prenons le fichier d'entrée suivant, s'il en existe toujours. Ceci est utile si vous avez de gros fichiers.
Un petit test:
kent$ head f*
==> f <==
hello hello world
==> f2 <==
hello
==> f3 <==
hello
hello
SK-Arch 22:27:00 /tmp/test
kent$ awk -v p="hello" 'FNR==1{x=0}{x+=gsub(p,p);if(x>1){print FILENAME;nextfile}}' f*
f
f3
Cette awk
imprimera le nom de tous les fichiers avec 2
ou plus Hello
awk 'FNR==1 {if (a>1) print f;a=0} /Hello/ {a++} {f=FILENAME} END {if (a>1) print f}' *
file2
file3
Ce dont vous avez besoin est une variable grep
capable de reconnaître les motifs entre les fins de ligne ( "bonjour" suivie de tout (éventuellement de fins de ligne), suivie de "bonjour" )
Étant donné que grep
traite vos fichiers ligne par ligne, il n’est pas (en lui-même) le bon outil pour le travail - sauf si vous parvenez à regrouper l’ensemble du fichier en une seule ligne.
Maintenant, c'est facile, par exemple, en utilisant la commande tr
, en remplaçant les fins de ligne par des espaces:
if cat $file | tr '\n' ' ' | grep -q 'hello.*hello'
then
echo "$file matches"
fi
Ceci est très efficace, même sur des fichiers volumineux comportant beaucoup (par exemple 100 000) lignes, et peut être encore plus efficace en appelant grep
avec --max-count=1
, ce qui permet d’arrêter la recherche après la recherche d’une correspondance. Peu importe que les deux bonjours soient sur la même ligne ou non.
grep -c Bonjour * | egrep -v ': [01] $' | sed 's /: [0-9] * $ //'
Autrement:
grep Hello * | cut -d: -f1 | uniq -d
Grep pour les lignes contenant 'Hello'; ne garder que les noms de fichiers; n'imprimez que les doublons.