Wie verwende ich eine Pipe im Parameter exec für einen Suchbefehl?

76

Ich versuche, einen Suchbefehl zu erstellen, um eine Reihe von Dateien in einem Verzeichnis mit zwei verschiedenen ausführbaren Dateien zu verarbeiten. Leider -execerlaubt on find die Verwendung von Pipe nicht oder auch nicht, \|weil die Shell dieses Zeichen zuerst interpretiert.

Hier ist genau das, was ich versuche (was nicht funktioniert, weil Pipe den Befehl find beendet):

find /path/to/jpgs -type f -exec jhead -v {} | grep 123 \; -print
Hoyhoy
quelle

Antworten:

86

Versuche dies

find /path/to/jpgs -type f -exec sh -c 'jhead -v {} | grep 123' \; -print

Alternativ können Sie versuchen, Ihre exec-Anweisung in ein sh-Skript einzubetten, und dann Folgendes tun:

find -exec some_script {} \;
Martin Marconcini
quelle
15

Ein etwas anderer Ansatz wäre die Verwendung von xargs:

find /path/to/jpgs -type f -print0 | xargs -0 jhead -v | grep 123

was ich immer ein bisschen leichter zu verstehen und anzupassen fand (die Argumente -print0 und -0 sind notwendig, um mit Dateinamen umzugehen, die Leerzeichen enthalten)

Dies ist möglicherweise (nicht getestet) effektiver als die Verwendung von -exec, da die Liste der Dateien an xargs weitergeleitet wird und xargs sicherstellt, dass die jhead-Befehlszeile nicht zu lang wird.

Palmin
quelle
4
Das Problem bei der Verwendung von xargs ist, dass ich den Namen der übereinstimmenden Datei benötige. Dieser Befehl findet die Übereinstimmungen, aber ich weiß nicht, welche Datei übereinstimmt.
Hoyhoy
4

Mit können -execSie nur eine einzige ausführbare Datei mit einigen Argumenten ausführen, nicht mit beliebigen Shell-Befehlen. Um dies zu umgehen, können Sie verwenden sh -c '<shell command>'.

Beachten Sie, dass die Verwendung von -execziemlich ineffizient ist. Für jede gefundene Datei muss der Befehl erneut ausgeführt werden. Es wäre effizienter, wenn Sie dies vermeiden könnten. (Zum Beispiel durch Verschieben der grepAußenseite -execoder Verrohrung der Ergebnisse von findto, xargswie von Palmin vorgeschlagen .)

mweerden
quelle
1
Eine andere Möglichkeit, die Ineffizienz mehrerer Prozesse im allgemeinen Fall zu vermeiden, ist die Verwendung von xargs. Wenn Sie separate Prozesse benötigen, können Sie die Option -i verwenden. Ich finde xargs eher im Einklang mit dem Unix-Modell.
Jon Ericson
1
AOL auf Xargs verwenden. mweerden, vielleicht solltest du deinen letzten absatz ändern, indem du die xargs existenz berücksichtigst. Beachten Sie auch das Flag -0, das sowohl in findals auch in vorhanden ist xargs.
Zot
3

Die Verwendung eines findBefehls für diese Art von Aufgabe ist möglicherweise nicht die beste Alternative. Ich verwende häufig den folgenden Befehl, um Dateien zu finden, die die angeforderten Informationen enthalten:

for i in dist/*.jar; do echo ">> $i"; jar -tf "$i" | grep BeanException; done
Dimitar
quelle
1

Da dies eine Liste ausgibt, würden Sie nicht:

find /path/to/jpgs -type f -exec jhead -v {} \; | grep 123

oder

find /path/to/jpgs -type f -print -exec jhead -v {} \; | grep 123

Setzen Sie Ihren Grep auf die Ergebnisse der find -exec.

Xetius
quelle
Das funktioniert nicht, weil ich den -print brauche, um zu arbeiten. Wenn grep einen Erfolg zurückgibt, druckt find den Dateinamen, andernfalls nicht.
Hoyhoy
0

Es gibt eine andere Möglichkeit, dies zu tun, aber es ist auch ein hübsches Ghetto.

Mit der Shell-Option extquote können Sie etwas Ähnliches tun, um Exec-Zeug zu finden und es dann an sh weiterzuleiten.

root@ifrit findtest # find -type f -exec echo ls $"|" cat \;|sh
filename


root@ifrit findtest # find -type f -exec echo ls $"|" cat $"|" xargs cat\;|sh
h

Ich dachte nur, ich würde das hinzufügen, weil es zumindest so, wie ich es mir vorgestellt habe, näher an der ursprünglichen Frage des OP war, Pipes in exec zu verwenden.

Linuxgeek
quelle