
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 grep
zweimal verwenden: a) zum Auflisten aller Dateien mit cat
und dann b) zum Aussortieren von dog
-haltigen Dateien. Verwenden Sie -l
bzw. -L
, wobei -l
Dateinamen mit Übereinstimmungen und -L
Dateinamen 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 grep
und xargs
( -R
das Sie bereits verwenden, ist grep
ohnehin eine GNU-Erweiterung, ist dort jedoch -r
vorzuziehen):
grep -rwlZ cat labels/ | xargs -r0 grep -wL dog
Würde die Dateien auflisten, die mindestens ein cat
Wort und kein dog
Wort enthalten (Wortin diesem Kontext bedeutet: "nicht umgeben vonWortzeichen",Wortzeichenalphanumerische Zeichen und Unterstrich). Ersetzen Sie -w
durch , -x
um 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 find
und GNU awk
(oder einem anderen awk
Programm, 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 perl
stattdessen 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.txt
ist 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