Risposte:
In GNU find
è possibile utilizzare i -printf
parametri per questo, ad esempio:
find /dir1 -type f -printf "%f\n"
-o
ha una precedenza inferiore a quella implicita -a
, quindi spesso vorrai raggruppare le tue -o
argomentazioni)
Se la tua ricerca non ha un'opzione -printf puoi anche usare basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Utilizzare ciò -execdir
che contiene automaticamente il file corrente {}
, ad esempio:
find . -type f -execdir echo '{}' ';'
Puoi anche usare $PWD
invece di .
(su alcuni sistemi non produrrà un punto in più nella parte anteriore).
Se hai ancora un punto in più, in alternativa puoi eseguire:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
Il
-execdir
primario è identico al-exec
primario con l'eccezione che l'utilità verrà eseguita dalla directory che contiene il file corrente .
Se utilizzato +
invece di ;
, {}
viene sostituito con il maggior numero di percorsi possibili per ogni chiamata di utilità. In altre parole, stamperà tutti i nomi di file in una riga.
./filename
invece di filename
. A seconda delle tue esigenze, potrebbe andare o no.
$PWD
invece di .
.
Se stai usando GNU find
find . -type f -printf "%f\n"
Oppure puoi usare un linguaggio di programmazione come Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Se hai voglia di una soluzione bash (almeno 4)
shopt -s globstar
for file in **; do echo ${file##*/}; done
Se vuoi eseguire qualche azione solo sul nome del file, usare basename
può essere difficile.
Ad esempio questo:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
farà l'eco di basename /my/found/path
. Non quello che vogliamo se vogliamo eseguire sul nome del file.
Ma puoi quindi xargs
l'output. ad esempio per uccidere i file in una directory in base ai nomi in un'altra directory:
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
e -execdir
sono lenti, xargs
è re.
$ 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
Il parallelismo aiuta anche.
Stranamente non riesco a spiegare l'ultimo caso di xargs
senza -n1
. Dà il risultato corretto ed è il più veloce¯\_(ツ)_/¯
( basename
accetta solo 1 argomento path ma xargs
li invierà tutti (in realtà 5000) senza -n1
. non funziona su linux e openbsd, solo macOS ...)
Alcuni numeri più grandi da un sistema Linux per vedere come -execdir
aiuta, ma ancora molto più lentamente di un parallelo 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
è -execdir
che diventa il più veloce in quanto la creazione di nuovi processi è un'operazione relativamente costosa.
Onestamente basename
e le dirname
soluzioni sono più facili, ma puoi anche dare un'occhiata:
find . -type f | grep -oP "[^/]*$"
o
find . -type f | rev | cut -d '/' -f1 | rev
o
find . -type f | sed "s/.*\///"
Come altri hanno sottolineato, è possibile combinare find
e basename
, ma per impostazione predefinita il basename
programma funzionerà solo su un percorso alla volta, quindi l'eseguibile dovrà essere lanciato una volta per ogni percorso (usando uno find ... -exec
o find ... | xargs -n 1
), che potrebbe essere potenzialmente lento.
Se usi l' -a
opzione on basename
, allora può accettare più nomi di file in una singola chiamata, il che significa che puoi quindi utilizzare xargs
senza il -n 1
, per raggruppare i percorsi in un numero molto più piccolo di chiamate basename
, che dovrebbero essere più efficienti.
Esempio:
find /dir1 -type f -print0 | xargs -0 basename -a
Qui ho incluso -print0
e -0
(che dovrebbe essere usato insieme), al fine di far fronte a qualsiasi spazio bianco all'interno dei nomi di file e directory.
Ecco un confronto temporale tra le versioni xargs basename -a
e xargs -n1 basename
. (Per un confronto simile a simile, i tempi riportati qui sono dopo una corsa fittizia iniziale, quindi entrambi vengono eseguiti dopo che i metadati del file sono già stati copiati nella cache I / O.) Ho reindirizzato l'output a cksum
in entrambi i casi, solo per dimostrare che l'output è indipendente dal metodo utilizzato.
$ 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
Come puoi vedere, è davvero molto più veloce evitare di lanciare basename
ogni volta.
basename
accetterà più nomi di file senza bisogno di ulteriori argomenti da riga di comando. L'uso di -a
qui è su Linux. ( basename --version
mi dice basename (GNU coreutils) 8.28
.)