grep gibt keine Ausgabe für ein in einer Variablen übergebenes Verzeichnis aus

grep gibt keine Ausgabe für ein in einer Variablen übergebenes Verzeichnis aus

Ich versuche, ein bashSkript zu schreiben, das den Inhalt von Dateien in einem angegebenen Verzeichnisbaum nach dem Vorhandensein einer angegebenen Teilzeichenfolge durchsucht.

Die Verwendung grepder rekursiven Funktion allein reicht nicht aus, da ich möglicherweise über das /Verzeichnis (und alle Unterverzeichnisse) eines Systems iterieren muss, was zu grepSpeichermangel und Abbruch führen kann. Daher habe ich mich entschieden, eine Liste aller Verzeichnisse und Unterverzeichnisse im angegebenen Verzeichnisbaum zu erhalten, wobei ich finddie folgenden Variablen verwende, die an das Skript übergebene Argumente bezeichnen.

searchdir=$HOME     # passed in a script argument
searchstr="secret"  # passed in a script argument

Ich rufe das findDienstprogramm auf und speichere die Ausgabe in einer temporären Datei.

TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null

Mit der Liste aller Verzeichnisse in der temporären Datei iteriere ich in einer while-doSchleife über die Zeilen dieser Datei mit der Absicht, eine Suche über alle Dateien in jedem Verzeichnis durchzuführen. Für grepverwende ich das Format der Parameter, das in angegeben istdiese Antwortum alle Dateien, einschließlich der versteckten, in einem einzelnen Verzeichnis zu suchen.

cat $TF | while read line || [[ -n $line ]];
do
    grepdir="${line}/{*,.*}"
    grep -sHn "${searchstr}" ${grepdir}
done

... dieser Code erzeugt jedoch keine Ausgabe.

Ich habe das überprüft …

Es ${TF}enthält die korrekte Liste aller Verzeichnisse. Die Ausgabe der ${grepdir}Variable ergibt die Ausgabe, die ich erwarte.

/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on

Wenn ich den grepBefehl mit einem fest codierten Verzeichnis ausführe, insbesondere dem ~/test/Verzeichnis, das zwei Testdateien mit der Zeichenfolge enthält, die gefunden werden soll

grep -sHn "${searchstr}" /home/user/test/{*,.*}

... es gibt die beiden Dateien korrekt aus, die die Teilzeichenfolge „geheim“ enthalten.

/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd

Ein Format, das für mich funktioniert, ist das ursprünglich erwähnte in derAntwort zur Diskussion der rekursiven Verwendung vongrep. Wenn ich dies mache:

cat $TF | while read line || [[ -n $line ]];
do
    grep -rn "${line}" -e "${searchstr}"
done

... Ich erhalte eine Ausgabe (technisch korrekt, aber mit vielen doppelten Einträgen), aber da grepdie Verzeichnisse rekursiv verarbeitet werden und ich eine Liste aller Verzeichnisse habe, werde ich zwangsläufig mehrmals dieselben Ergebnisse erhalten und bei Verzeichnissen wie dem oben erwähnten Stammverzeichnis grepwird ein vollständiger Fehler auftreten, was ich jedoch vermeiden möchte.


Ich sollte wahrscheinlich auch erwähnen, dass meine verzweifelten Versuche, es zum Laufen zu bringen, wie etwa die Übergabe $(echo "${grepdir}")als Parameter, ebenfalls zu keinen Ergebnissen führten.

Wahrscheinlich liegt ein Missverständnis in meinem Denken oder Verständnis von vor bash. Sollte bashdie ${grepdir}Variable nicht erweitert werden, bevor ein Aufruf von erfolgt grep? Wo liegt in meinem Skript ein Fehler?

Antwort1

Regel Nr. 1: Wenn ein Befehl oder Skript nicht das tut, was Sie möchten, Schauen Sie sich die Fehlermeldungen an.  Werfen Sie sie nicht hinein  /dev/null.

Sie erhalten Fehlermeldungen wie

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

aber Sie sehen sie nicht.

Wenn wir uns ansehenbash(1), wir sehen

Die Erweiterung wird in der Befehlszeile durchgeführt, nachdem diese in Wörter aufgeteilt wurde. Es gibt sieben Arten der Erweiterung: Klammernerweiterung, Tilde-Erweiterung, Parameter- und Variablenerweiterung, Befehlsersetzung, arithmetische Erweiterung, Wortaufteilung und Pfadnamenerweiterung.

Die Reihenfolge der Erweiterungen ist: Klammernerweiterung, Tilde-Erweiterung, Parameter- und Variablenerweiterung, arithmetische Erweiterung und Befehlsersetzung (von links nach rechts durchgeführt), Worttrennung und Pfadnamenerweiterung.

Der wichtige Teil für Ihre Situation ist, dass die Klammererweiterung vor der Variablenerweiterung erfolgt. Wenn Sie also sagen:

grep -sHn "${searchstr}" "${line}"/{*,.*}

Dann

  • Die Klammererweiterung würde das letzte Token in "${line}"/*und verwandeln "${line}"/.*,
  • Die Variablenerweiterung würde das obige in /home/user/*und umwandeln /home/user/.*, und dann
  • Die Pfadnamenerweiterung würde das Obige in eine Liste von Dateinamen umwandeln.

Aber wenn Sie sagen

grep -sHn "${searchstr}" ${grepdir}

Dann

  • Die Variablenerweiterung verwandelt das letzte Token in /home/user/{*,.*},

und dann ist es für eine Klammernerweiterung zu spät.  grepsucht nach einer Datei mit dem wörtlichen Namen /home/user/{*,.*}.


PS

grep -sHn "${searchstr}" "${line}/{*,.*}"

würde auch nicht funktionieren, da die Anführungszeichen die Klammern- und Pfadnamenerweiterung verhindern würden.

PPS: Sie brauchen nicht alle diese Zahnspangen;

grep -sHn "$searchstr" "$line"/{*,.*}

wäre in Ordnung.

Antwort2

Der Grund, warum grep beim rekursiven Durchlaufen des gesamten Systems abbricht, liegt wahrscheinlich nicht darin, dass es mit der Datenmenge nicht zurechtkommt, sondern darin, dass es über die eine oder andere Pseudo- oder Gerätedatei in /proc, /sys oder /dev stolpert. Mit der --excludeOption auf der Kommandozeile könnte man die betreffenden Verzeichnisse ausschließen.

Der Grund, warum die Platzhalter nicht erweitert werden, liegt darin, dass sie in dieser Zeile in Anführungszeichen stehen:

    grepdir="${line}/{*,.*}"

Eine entsprechende Änderung wird wahrscheinlich dazu beitragen, dass sie erweitert werden.

    grepdir="${line}/"{*,.*}

Eine andere Möglichkeit, dies zu erreichen (mit weniger Skripting Ihrerseits), besteht darin, die Dateien auszuwählen findund die Dateipfade xargszur Verarbeitung weiterzuleiten:find / ... -print 0 | xargs -0 ...

In beiden Fällen würden Sie jedoch wahrscheinlich trotzdem über die Dateien stolpern, über die das ursprüngliche rekursive Grep gestolpert ist, sofern Sie sie nicht ausschließen.

verwandte Informationen