Antworten:
In GNU können find
Sie dafür -printf
Parameter verwenden, z.
find /dir1 -type f -printf "%f\n"
-o
eine niedrigere Priorität als impliziert hat -a
, so dass Sie häufig Ihre -o
Argumente gruppieren möchten )
Wenn Ihr Fund keine Option -printf hat, können Sie auch den Basisnamen verwenden:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Verwenden Sie -execdir
diese Option, in der die aktuelle Datei automatisch gespeichert ist {}
, zum Beispiel:
find . -type f -execdir echo '{}' ';'
Sie können auch $PWD
anstelle von verwenden .
(auf einigen Systemen wird vorne kein zusätzlicher Punkt erzeugt).
Wenn Sie noch einen zusätzlichen Punkt haben, können Sie alternativ Folgendes ausführen:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
Die
-execdir
Primärdatenbank ist mit der-exec
Primärdatenbank identisch, mit der Ausnahme, dass das Dienstprogramm aus dem Verzeichnis ausgeführt wird, in dem sich die aktuelle Datei befindet .
Bei Verwendung +
anstelle von ;
wird dann {}
bei jedem Aufruf des Dienstprogramms durch so viele Pfadnamen wie möglich ersetzt. Mit anderen Worten, es werden alle Dateinamen in einer Zeile gedruckt.
./filename
statt filename
. Abhängig von Ihren Bedürfnissen kann es in Ordnung sein oder auch nicht.
$PWD
statt .
.
Wenn Sie GNU verwenden, finden Sie
find . -type f -printf "%f\n"
Oder Sie können eine Programmiersprache wie Ruby (1.9+) verwenden.
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Wenn Sie Lust auf eine Bash-Lösung (mindestens 4) haben
shopt -s globstar
for file in **; do echo ${file##*/}; done
Wenn Sie eine Aktion nur für den Dateinamen ausführen möchten, basename
kann die Verwendung schwierig sein.
Zum Beispiel dies:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
wird nur den Basisnamen wiedergeben /my/found/path
. Nicht das, was wir wollen, wenn wir den Dateinamen ausführen wollen.
Aber das kannst du dann xargs
die Ausgabe. Zum Beispiel, um die Dateien in einem Verzeichnis basierend auf Namen in einem anderen Verzeichnis zu beenden:
cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
-exec
und -execdir
sind langsam, xargs
ist König.
$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l
139
0m01.17s real 0m00.20s user 0m00.93s system
139
0m01.16s real 0m00.20s user 0m00.92s system
139
0m01.05s real 0m00.17s user 0m00.85s system
139
0m00.93s real 0m00.17s user 0m00.85s system
139
0m00.88s real 0m00.12s user 0m00.75s system
xargs
Die Parallelität hilft auch.
Lustigerweise kann ich den letzten Fall von xargs
ohne nicht erklären-n1
. Es gibt das richtige Ergebnis und es ist das schnellste¯\_(ツ)_/¯
( basename
Dauert nur 1 Pfad Argument aber xargs
, ohne sie alle (tatsächlich 5000) senden -n1
. Nicht die Arbeit an Linux und openbsd, nur macOS ...)
Einige größere Zahlen von einem Linux-System, um zu sehen, wie -execdir
hilft, aber immer noch viel langsamer als eine Parallele xargs
:
$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l
2358
3.63s real 0.10s user 0.41s system
2358
1.53s real 0.05s user 0.31s system
2358
1.30s real 0.03s user 0.21s system
2358
0.41s real 0.03s user 0.25s system
find
ist es , -execdir
dass die schnellst als die Schaffung neue Verfahren wird ein relativ teurer Betrieb ist.
Wie andere bereits betont haben, können Sie find
und kombinieren. basename
Standardmäßig wird das basename
Programm jedoch jeweils nur auf einem Pfad ausgeführt. Daher muss die ausführbare Datei für jeden Pfad einmal gestartet werden (entweder find ... -exec
oder find ... | xargs -n 1
), was möglicherweise langsam ist.
Wenn Sie die -a
Option aktivieren basename
, können mehrere Dateinamen in einem einzigen Aufruf akzeptiert werden. Dies bedeutet, dass Sie die Pfade xargs
ohne die Option -n 1
zu einer weitaus geringeren Anzahl von Aufrufen von gruppieren können basename
, was effizienter sein sollte.
Beispiel:
find /dir1 -type f -print0 | xargs -0 basename -a
Hier habe ich das -print0
und aufgenommen-0
(das zusammen verwendet werden sollte) eingefügt, um mit Leerzeichen in den Namen von Dateien und Verzeichnissen fertig zu werden.
Hier ist ein Zeitvergleich zwischen xargs basename -a
und xargs -n1 basename
Versionen. (Um einen Vergleich mit ähnlichen Daten zu ermöglichen, werden die hier angegebenen Timings nach einem ersten Dummy-Lauf angezeigt, sodass beide ausgeführt werden, nachdem die Dateimetadaten bereits in den E / A-Cache kopiert wurden.) Ich habe die Ausgabe an weitergeleitet cksum
In beiden Fällen nur, um zu demonstrieren, dass die Ausgabe unabhängig von der verwendeten Methode ist.
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663
real 0m0.063s
user 0m0.058s
sys 0m0.040s
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum'
2532163462 546663
real 0m14.504s
user 0m12.474s
sys 0m3.109s
Wie Sie sehen, ist es wesentlich schneller, nicht basename
jedes Mal zu starten .
basename
mehrere Dateinamen akzeptiert werden, ohne dass zusätzliche Befehlszeilenargumente erforderlich sind. Die Verwendung von -a
hier ist unter Linux. ( basename --version
sagt es mir basename (GNU coreutils) 8.28
.)