
Wie führe ich einen Befehl aus, bei dem eine Datei gefunden wird?
Angenommen, ich habe ein Verzeichnis mit dem Namen testdir
, das Folgendes enthält:
$ ls -R testdir/
testdir/:
dir1 dir2 dir3 dir4 dir5
testdir/dir1:
doc1.pdf
testdir/dir2:
file1.txt
testdir/dir3:
doc2.pdf
testdir/dir4:
file2.txt
testdir/dir5:
doc5.pdf
Jetzt möchte ich eine Aktion ausführen (einen Befehl ausführen), bei der find
eine bestimmte Datei/ein bestimmter Dateityp gefunden wird. Lassen Sie mich beispielsweise Folgendes finden *.pdf
:
$ find . -name '*.pdf'
./testdir/dir3/doc2.pdf
./testdir/dir5/doc5.pdf
./testdir/dir1/doc1.pdf
Nehmen wir nun an, ich möchte einen Befehl ausführen (sagen wir zum Beispiel ), bei dem der obige Befehl Dateien findet. Mit anderen Worten, ich möchte in jedem Verzeichnis, in dem mindestens eine Datei gefunden wurde touch file
, eine Datei mit dem Namen erstellen, sodass ich Folgendes erhalte:file
.pdf
$ ls -R testdir/
testdir/:
dir1 dir2 dir3 dir4 dir5
testdir/dir1:
doc1.pdf file
testdir/dir2:
file1.txt
testdir/dir3:
doc2.pdf file
testdir/dir4:
file2.txt
testdir/dir5:
doc5.pdf file
Wie erledige ich so etwas?
Vielleicht jedes Mal, wenn eine Datei gefunden wird, cd
dorthin gehen, wo die Datei existiert, und einen Befehl rekursiv ausführen.
Ich weiß, dass das find
eine tolle Funktion ist, -exec
aber ich bekomme es nicht zum Laufen.
Dies ist nur ein Beispiel, um eine Vorstellung davon zu bekommen, was ich tun möchte. Allgemein: Wie führe ich einen Befehl aus, bei dem Dateien (durch find
) rekursiv gefunden werden?
Antwort1
Wenn Sie diesen Befehl ausführen touch file
, wird er möglicherweise mehrmals aus dem Verzeichnis ausgeführt, in dem der Befehl gestartet wurde:
find -name '*.pdf' -exec touch file \;
Wenn Sie hingegen diese Variante ausführen, wird jede Instanz des Befehls im Verzeichnis der Zieldatei ausgeführt:
find -name '*.pdf' -execdir touch file \;
In beiden Fällen können Sie dies in Aktion sehen, indem Sie touch file
durch echo {}
und/oder ersetzen pwd
.
Aus der Manpage:
-execdir command ;
-execdir command {} +
Wie
-exec
, aber der angegebene Befehl wird aus dem Unterverzeichnis ausgeführt, das die übereinstimmende Datei enthält. Dies ist normalerweise nicht das Verzeichnis, in dem Sie gestartet habenfind
.
Antwort2
Sie können das Verzeichnis des Dateinamens extrahieren dirname
und die Datei von dort übernehmen, etwa so:
find . -name "*.pdf" -type f -exec bash myscript {} \;
Die Datei myscript
enthält Folgendes:
dir=$(dirname "$1")
cd "$dir"
touch file
Antwort3
Mit zsh
könnten Sie Glob-Qualifizierer verwenden, um beispielsweise nur Dateien auszuwählen .pdf
und überModifikatorenSpeichern Sie die Verzeichnisnamen in einem Array miteinzigartigElemente und dann cd
in jedes dieser Verzeichnisse und führen Sie Ihren Befehl aus. Auf diese Weise führen Sie Ihren Befehl nur auseinmalin jedem Verzeichnis, unabhängig von der Anzahl der .pdf
s, die in diesem Verzeichnis gefunden wurden:
dirlist=(**/*.pdf(.:a:h))
for d in ${(u)dirlist[@]}
(cd $d && touch file)
oder
typeset -U dirlist
dirlist=(**/*.pdf(.:a:h))
for d in ${dirlist}
(cd $d && touch file)
Sie können Modifikatoren und Qualifikatoren weiter kombinieren, um beispielsweise für reguläre Dateien (versteckte und nicht versteckte) einen Glob mit der Erweiterung zu erstellen .bkp
und eindeutige Verzeichnisnamen in einem Array zu speichern:
dirlist=(**/*.bkp(D.:a:h))
Antwort4
Suchen Sie nicht weiter als entr:
https://bitbucket.org/eradman/entr
Sie können entr ein bestimmtes Verzeichnis überwachen lassen. Wenn find die Datei findet, berühren Sie eine Datei namens triggerfile.txt in diesem Verzeichnis und lassen Sie entr übernehmen.