web-dev-qa-db-fra.com

grep pour plusieurs chaînes dans le fichier sur différentes lignes (c.-à-d. un fichier entier, pas une recherche basée sur une ligne)

Je veux grep pour les fichiers contenant les mots Dansk, Svenska ou Norsk sur une ligne, avec un code de retour utilisable (comme je n'aime vraiment que l'information que les chaînes sont contenues, mon one-liner va un peu plus loin que cela).

J'ai beaucoup de fichiers avec des lignes comme celles-ci:

Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
        Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20, 
        Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21, 
        Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22, 
        Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23, 
        Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24, 
(...)

Voici le pseudocode de ce que je veux:

for all files in directory;
 if file contains "Dansk" AND "Norsk" AND "Svenska" then
 then echo the filename
end

Quelle est la meilleure façon de procéder? Cela peut-il être fait sur une seule ligne?

76
Christian

Vous pouvez utiliser: 

grep -l Dansk * | xargs grep -l Norsk | xargs grep -l Svenska

Si vous voulez aussi trouver dans des fichiers cachés:

grep -l Dansk .* | xargs grep -l Norsk | xargs grep -l Svenska
81
vmpstr

Encore une autre façon d’utiliser simplement bash et grep:

Pour un seul fichier 'test.txt':

 grep -q Dansk test.txt && grep -q Norsk test.txt && grep -l Svenska test.txt 

Imprimera test.txt si le fichier contient les trois (quelle que soit la combinaison). Les deux premiers greps n'impriment rien (-q) et le dernier n'imprime le fichier que si les deux autres ont réussi.

Si vous voulez le faire pour chaque fichier du répertoire:

 pour f dans *; do grep -q Dansk $ f && grep -q Norsk $ f && grep -l Svenska $ f; terminé
21
Edd Steel
grep –irl Word1 * | grep –il Word2 `cat -` | grep –il Word3 `cat -`
  • -i rend la recherche insensible à la casse
  • -r rend la recherche de fichier récursive dans les dossiers
  • -l dirige la liste des fichiers avec le mot trouvé
  • cat - amène le prochain grep à parcourir les fichiers qui lui sont transmis.
12
Gerry

Comment grep pour plusieurs chaînes dans un fichier sur différentes lignes (utilisez le symbole du canal):

for file in *;do 
   test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file
done

Remarques:

  1. Si vous utilisez des guillemets "" avec votre grep, vous devrez vous échapper du tube comme ceci: \| pour rechercher Dansk, Norsk et Svenska.

  2. Suppose qu'une ligne n'a qu'une seule langue.

Procédure pas à pas: http://www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/

9
Damodharan R

Vous pouvez le faire très facilement avec ack :

ack -l 'cats' | ack -xl 'dogs'
  • -l: retourne une liste de fichiers 
  • -x: prend les fichiers de STDIN (la recherche précédente) et ne cherche que ces fichiers

Et vous pouvez simplement continuer à jouer jusqu'à ce que vous obteniez uniquement les fichiers souhaités.

5
Ben Johnson

Ceci recherche plusieurs mots dans plusieurs fichiers:

egrep 'abc|xyz' file1 file2 ..filen 
5
Sarath Chandra
awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }' 

vous pouvez alors attraper la valeur de retour avec le shell

si vous avez Ruby (1.9+)

Ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file
4
kurumi

Simplement:

grep 'Word1\|Word2\|Word3' *

voir cet article pour plus d'informations

3
moshe beeri

Il s'agit d'un mélange de réponses de glenn jackman et de kurumi qui permet un nombre arbitraire de regex au lieu d'un nombre arbitraire de mots fixes ou d'un ensemble fixe de regex.

#!/usr/bin/awk -f
# by Dennis Williamson - 2011-01-25

BEGIN {
    for (i=ARGC-2; i>=1; i--) {
        patterns[ARGV[i]] = 0;
        delete ARGV[i];
    }
}

{
    for (p in patterns)
        if ($0 ~ p)
            matches[p] = 1
            # print    # the matching line could be printed
}

END {
    for (p in patterns) {
        if (matches[p] != 1)
            exit 1
    }
}

Exécutez-le comme ça:

./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat
2
Dennis Williamson

En développant la réponse awk de @ kurumi, voici une fonction bash:

all_Word_search() {
    gawk '
        BEGIN {
            for (i=ARGC-2; i>=1; i--) {
                search_terms[ARGV[i]] = 0;
                ARGV[i] = ARGV[i+1];
                delete ARGV[i+1];
            }
        }
        {
            for (i=1;i<=NF; i++) 
                if ($i in search_terms) 
                    search_terms[$1] = 1
        }
        END {
            for (Word in search_terms) 
                if (search_terms[Word] == 0) 
                    exit 1
        }
    ' "$@"
    return $?
}

Usage:

if all_Word_search Dansk Norsk Svenska filename; then
    echo "all words found"
else
    echo "not all words found"
fi
1
glenn jackman

Voici ce qui a bien fonctionné pour moi:

find . -path '*/.svn' -Prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
./another/path/to/file2.txt
./blah/foo.php

Si je voulais juste trouver des fichiers .sh avec ces trois fichiers, j'aurais pu utiliser:

find . -path '*/.svn' -Prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
1
Nick Henry

Je l'ai fait en deux étapes. Dressez une liste des fichiers csv dans un fichier Avec l’aide de cette page de commentaires, j’ai fait deux étapes sans script pour obtenir ce dont j'avais besoin. Il suffit de taper dans le terminal:

$ find /csv/file/dir -name '*.csv' > csv_list.txt
$ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`

il a fait exactement ce dont j'avais besoin - imprimer les noms de fichiers contenant les trois mots. 

Attention aussi aux symboles comme `' "

1
Simas

J'ai eu ce problème aujourd'hui, et tous les monolignes ici ont échoué parce que les fichiers contenaient des espaces dans les noms.

Voici ce que j'ai trouvé qui a fonctionné:

grep -ril <Word1> | sed 's/.*/"&"/' | xargs grep -il <Word2>
0
giusti

Si vous n'avez besoin que de deux termes de recherche, l'approche la plus lisible consiste à lancer chaque recherche et à intersecter les résultats:

 comm -12 <(grep -rl Word1 . | sort) <(grep -rl Word2 . | sort)
0
Ankur Dave