Respuestas:
En GNU find
puede usar -printf
parámetros para eso, por ejemplo:
find /dir1 -type f -printf "%f\n"
-o
tiene menor precedencia que implicaba -a
, por lo que a menudo tendrá que agrupar sus -o
argumentos)
Si su búsqueda no tiene una opción -printf, también puede usar basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Uso -execdir
que contiene automáticamente el archivo actual {}
, por ejemplo:
find . -type f -execdir echo '{}' ';'
También puede usar en $PWD
lugar de .
(en algunos sistemas no producirá un punto extra en el frente).
Si aún tiene un punto extra, también puede ejecutar:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
El
-execdir
primario es idéntico al-exec
primario con la excepción de que la utilidad se ejecutará desde el directorio que contiene el archivo actual .
Cuando se usa en +
lugar de ;
, {}
se reemplaza con la mayor cantidad de rutas posibles para cada invocación de la utilidad. En otras palabras, imprimirá todos los nombres de archivo en una línea.
./filename
lugar de filename
. Dependiendo de sus necesidades, puede o no estar bien.
$PWD
lugar de .
.
Si está utilizando GNU encuentre
find . -type f -printf "%f\n"
O puede usar un lenguaje de programación como Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Si te apetece una solución bash (al menos 4)
shopt -s globstar
for file in **; do echo ${file##*/}; done
Si desea ejecutar alguna acción solo contra el nombre del archivo, el uso basename
puede ser difícil.
Por ejemplo esto:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
solo hará eco de nombre base /my/found/path
. No es lo que queremos si queremos ejecutar el nombre del archivo.
Pero puedes entonces xargs
la salida. por ejemplo, para eliminar los archivos en un directorio basado en nombres en otro directorio:
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
y -execdir
son lentos, xargs
es rey.
$ 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
El paralelismo también ayuda.
Curiosamente, no puedo explicar el último caso de xargs
fuera -n1
. Da el resultado correcto y es el más rápido.¯\_(ツ)_/¯
( basename
toma solo 1 argumento de ruta pero xargs
los enviará a todos (en realidad 5000) sin -n1
. no funciona en Linux y OpenBSD, solo macOS ...)
Algunos números más grandes de un sistema Linux para ver cómo -execdir
ayuda, pero aún mucho más lento que un paralelo 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
es -execdir
que se convierte en el más rápido ya que crear nuevos procesos es una operación relativamente costosa.
Honestamente basename
y dirname
soluciones son más fáciles, pero también se puede comprobar esto:
find . -type f | grep -oP "[^/]*$"
o
find . -type f | rev | cut -d '/' -f1 | rev
o
find . -type f | sed "s/.*\///"
Como otros han señalado, puede combinar find
y basename
, pero de manera predeterminada, el basename
programa solo funcionará en una ruta a la vez, por lo que el ejecutable tendrá que iniciarse una vez para cada ruta (usando find ... -exec
o find ... | xargs -n 1
), lo que puede ser lento.
Si usa la -a
opción activada basename
, puede aceptar múltiples nombres de archivo en una sola invocación, lo que significa que puede usar xargs
sin el -n 1
, para agrupar las rutas en un número mucho menor de invocaciones basename
, lo que debería ser más eficiente.
Ejemplo:
find /dir1 -type f -print0 | xargs -0 basename -a
Aquí he incluido el -print0
y -0
(que deben usarse juntos), para hacer frente a cualquier espacio en blanco dentro de los nombres de archivos y directorios.
Aquí hay una comparación de tiempos, entre las versiones xargs basename -a
y xargs -n1 basename
. (En aras de una comparación de igual a igual, los tiempos que se informan aquí son posteriores a una ejecución ficticia inicial, de modo que ambos se realizan después de que los metadatos del archivo ya se hayan copiado en la caché de E / S). cksum
en ambos casos, solo para demostrar que la salida es independiente del método utilizado.
$ 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
Como puede ver, es mucho más rápido evitar el lanzamiento basename
cada vez.
basename
aceptará múltiples nombres de archivos sin necesidad de argumentos adicionales en la línea de comandos. El uso de -a
aquí está en Linux. ( basename --version
me dice basename (GNU coreutils) 8.28
)