Das funktioniert nicht. Kann das in find gemacht werden? Oder muss ich xargs verwenden?
find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;
Das funktioniert nicht. Kann das in find gemacht werden? Oder muss ich xargs verwenden?
find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;
Das, was der Auftraggeber erreichen wollte, kann mit den oben genannten Vorschlägen erreicht werden, aber dies ist derjenige, der die gestellte Frage tatsächlich beantwortet. Es gibt Gründe, es auf diese Weise zu tun - exec ist viel leistungsfähiger als die Dateien, die von find zurückgegeben werden, insbesondere in Kombination mit test. Zum Beispiel: find geda-gaf/ -type d -exec bash -c 'DIR={}; [[ $(find $DIR -maxdepth 1 |xargs grep -i spice |wc -l) -ge 5 ]] && echo $DIR' \; Gibt alle Verzeichnisse im Suchpfad zurück, die insgesamt mehr als 5 Zeilen von allen Dateien in diesem Verzeichnis enthalten, die das Wort spice
Beste Antwort. Das Grepen der gesamten Ausgabe (wie andere Antworten nahelegen) ist nicht dasselbe wie das Grepen jeder einzelnen Datei. Tipp: Anstelle von sh können Sie eine beliebige andere Shell verwenden (ich habe das mit bash ausprobiert und es läuft gut).
Achten Sie darauf, dass Sie nicht die -c
Option. Andernfalls erhalten Sie eine verwirrende No such file or directory
Fehlermeldung.
Die Aufgabe, das Pipe-Symbol als Anweisung zu interpretieren, mehrere Prozesse laufen zu lassen und die Ausgabe eines Prozesses in die Eingabe eines anderen Prozesses zu leiten, liegt in der Verantwortung der Shell (/bin/sh oder gleichwertig).
In Ihrem Beispiel können Sie entweder Ihre Top-Level-Shell verwenden, um das Piping wie folgt durchzuführen:
find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'
Im Hinblick auf die Effizienz kostet dies einen Aufruf von find, zahlreiche Aufrufe von zcat und einen Aufruf von agrep.
Dies würde dazu führen, dass nur ein einziger agrep-Prozess gestartet wird, der die gesamte Ausgabe, die durch zahlreiche Aufrufe von zcat erzeugt wird, verarbeitet.
Wenn Sie aus irgendeinem Grund agrep mehrfach aufrufen möchten, können Sie das tun:
find . -name 'file_*' -follow -type f \
-printf "zcat %p | agrep -dEOE 'grep'\n" | sh
Dies erstellt eine Liste von auszuführenden Befehlen mit Hilfe von Pipes und sendet diese dann an eine neue Shell, damit sie tatsächlich ausgeführt werden. (Das Weglassen des abschließenden "| sh" ist ein guter Weg, um solche Befehlszeilen zu debuggen oder Probeläufe durchzuführen).
Was die Effizienz betrifft, so kostet dies einen Aufruf von find, einen Aufruf von sh, zahlreiche Aufrufe von zcat und zahlreiche Aufrufe von agrep.
Die effizienteste Lösung im Hinblick auf die Anzahl der Befehlsaufrufe ist der Vorschlag von Paul Tomblin:
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'
... das kostet einen Aufruf von find, einen Aufruf von xargs, ein paar Aufrufe von zcat und einen Aufruf von agrep.
Ein weiterer Vorteil von xargs ist, dass man es mit modernen Mehrkern-CPUs noch weiter beschleunigen kann, indem man den -P Schalter (-P 0) verwendet.
Ja, der Schalter -P ist in der Tat eine gute Möglichkeit, die Ausführung im Allgemeinen zu beschleunigen. Leider besteht die Gefahr, dass die Ausgaben paralleler zcat-Prozesse in agrep verschachtelt werden, was das Ergebnis beeinflussen würde. Dieser Effekt kann mit echo -e "1" demonstriert werden. \n2 " | xargs -P 0 -n 1 yes | uniq
Ich hoffe, dass ich -print und xargs aus Gründen der Effizienz vermeiden kann. Vielleicht ist das wirklich mein Problem: find kann nicht mit gepipten Befehlen durch -exec umgehen
Dies funktioniert nicht mit Dateien, die Leerzeichen im Namen haben; um dies zu beheben, ersetzen Sie -print durch -print0 und fügen Sie die Option -0 zu xargs hinzu
@someguy - Was? Vermeiden Sie xargs aus Effizienzgründen? Eine Instanz von zcat aufzurufen und ihr eine Liste von mehreren Dateien zu übergeben, ist weit effizienter, als für jede gefundene Datei eine neue Instanz des Programms auszuführen.
Sie können auch eine Leitung zu einer while
Schleife, die mehrere Aktionen mit der Datei durchführen kann, die find
verortet. Hier ist also einer zum Reinschauen jar
Archive für eine bestimmte Java-Klassendatei in einem Ordner mit einer großen Anzahl von jar
Dateien
find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done
der wichtigste Punkt ist, dass die while
Schleife enthält mehrere Befehle, die auf den übergebenen Dateinamen verweisen, getrennt durch Semikolon, und diese Befehle können Pipes enthalten. In diesem Beispiel gebe ich also den Namen der passenden Datei aus und liste dann auf, was sich im Archiv befindet, indem ich nach einem bestimmten Klassennamen filtere. Die Ausgabe sieht wie folgt aus:
/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800.jar org/eclipse/core/databinding/observable/list/ IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar /usr/lib/eclipse/plugins/org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar /usr/lib/eclipse/plugins/org.eclipse.help.appserver_3.1.400.v20090429_1800.jar
in meiner Bash-Shell (xubuntu10.04/xfce) wird der übereinstimmende Klassenname tatsächlich fett dargestellt, da die fgrep
hebt die übereinstimmende Zeichenkette hervor; dies macht es sehr einfach, die Liste von Hunderten von jar
Dateien, die durchsucht wurden, und sehen Sie leicht alle Übereinstimmungen.
unter Windows können Sie das Gleiche tun:
for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList
Beachten Sie, dass unter Windows das Befehlstrennzeichen '&' und nicht ';' ist und dass das '@' das Echo des Befehls unterdrückt, um eine ordentliche Ausgabe zu erhalten, genau wie die obige Linux-Find-Ausgabe; obwohl findstr
macht die übereinstimmende Zeichenkette nicht fett, so dass Sie sich die Ausgabe etwas genauer ansehen müssen, um den übereinstimmenden Klassennamen zu erkennen. Es stellt sich heraus, dass der Windows-Befehl "for" einige Tricks kennt, wie z. B. das Durchlaufen von Textdateien in einer Schleife...
genießen Sie
Wenn Sie eine einfache Alternative suchen, können Sie dies mit einer Schleife tun:
for i in $(find -name 'file_*' -follow -type f); do
zcat $i | agrep -dEOE 'grep'
done
oder in einer allgemeineren und leichter verständlichen Form:
for i in $(YOUR_FIND_COMMAND); do
YOUR_EXEC_COMMAND_AND_PIPES
done
und ersetzen Sie alle {} durch $i in YOUR_EXEC_COMMAND_AND_PIPES
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.