So erhalten Sie Namen der Dateien, die nur den angegebenen Text enthalten

So erhalten Sie Namen der Dateien, die nur den angegebenen Text enthalten

Ich habe ein Verzeichnis namens „Labels“, in dem sich Textdateien befinden, die in separaten Zeilen Bezeichnungen für „Katze“ oder „Hund“ oder beides enthalten.
Die Inhalte der Dateien im Verzeichnis „Labels“ sind:

cat labels/1.txt
cat

cat labels/2.txt
dog

cat labels/3.txt
cat  
dog

Ich möchte die Namen von Dateien erhalten, die nur das Label „cat“ enthalten. Ich habe folgenden Befehl ausprobiert:

ls labels | grep -Rwl "cat"   
labels/1.txt  
labels/3.txt  

Dieser Befehl gibt jedoch die Namen der Dateien zurück, die „cat“ oder beides enthalten. Meine Anforderung ist jedoch, die Dateinamen zu erhalten, die nur „cat“ enthalten, nicht sowohl „cat“ als auch „dog“.
Dasselbe gilt, wenn ich versuche, die Namen der Dateien zu erhalten, die nur „dog“ enthalten. Wenn ich auf die gleiche Weise suche, werden Dateinamen zurückgegeben, die „dog“ oder beide Bezeichnungen enthalten.

ls labels | grep -Rwl "dog"
labels/2.txt  
labels/3.txt  

Antwort1

Sie können es grepzweimal verwenden: a) zum Auflisten aller Dateien mit catund dann b) zum Aussortieren von dog-haltigen Dateien. Verwenden Sie -lbzw. -L, wobei -lDateinamen mit Übereinstimmungen und -LDateinamen ohne Übereinstimmungen aufgelistet werden:

grep -L 'dog' $(grep -l 'cat' <list of files>)

Sehen man grep:

-L, --files-without-match

Unterdrückt die normale Ausgabe; druckt stattdessen den Namen jeder Eingabedatei, von der normalerweise keine Ausgabe gedruckt worden wäre. Der Scan wird bei der ersten Übereinstimmung angehalten.

-l, --files-with-matches

Unterdrückt die normale Ausgabe. Druckt stattdessen den Namen jeder Eingabedatei, aus der normalerweise eine Ausgabe gedruckt worden wäre. Der Scan wird bei der ersten Übereinstimmung angehalten.

Antwort2

Mit GNU grepund xargs( -Rdas Sie bereits verwenden, ist grepohnehin eine GNU-Erweiterung, ist dort jedoch -rvorzuziehen):

grep -rwlZ cat labels/ | xargs -r0 grep -wL dog

Würde die Dateien auflisten, die mindestens ein catWort und kein dogWort enthalten (Wortin diesem Kontext bedeutet: "nicht umgeben vonWortzeichen",Wortzeichenalphanumerische Zeichen und Unterstrich). Ersetzen Sie -wdurch , -xum nach Zeilen zu suchen, deren gesamter InhaltIst cat/ dog.

Antwort3

Wenn Sie die Namen der Dateien auflisten möchten, die „cat“, aber nicht „dog“ enthalten, versuchen Sie Folgendes unter Verwendung von findund GNU awk(oder einem anderen awkProgramm, das Blöcke unterstützt ENDFILE, da dies eine GNU-Erweiterung für ist awk):

$ find labels/ -type f -exec awk -v IGNORECASE=1 '
    /\<cat\>/ { cat = 1 };
    /\<dog\>/ { dog = 1 };

    ENDFILE {
      if (cat == 1 && dog == 0) {
        print FILENAME
      };
      cat = 0;
      dog = 0;
    }' {} +
labels/file1.txt

Oder Sie verwenden perlstattdessen awk:

$ find labels/ -type f -exec perl -l -n -e  '
    $cat = 1 if m/\bcat\b/i;
    $dog = 1 if m/\bdog\b/i;
    if (eof) {
      print $ARGV if ($cat && ! $dog);
      $cat=0;
      $dog=0;
    }' {} +
labels/file1.txt

Die Ausgabe der obigen Awk- und Perl-Versionen wurde mit den folgenden Dateien im labels/Unterverzeichnis erzeugt:

$ tail labels/*
==> labels/file1.txt <==
cat

==> labels/file2.txt <==
dog

==> labels/file3.txt <==
cat
dog

labels/file1.txtist der einzige Dateiname, der gedruckt wird, da es die einzige Datei ist, die „Katze“ enthält, aber nicht „Hund“.

Antwort4

for f in *; do diff -q <(sort -u "$f") <(echo cat) >/dev/null && echo "$f"; done

verwandte Informationen