¿Cómo usar el comando buscar para listar nombres de archivos pero no rutas?
Revisé algunas respuestas en línea, pero no funcionan cuando hay un -name
parámetro en el comando (tal vez estoy haciendo algo mal, no estoy seguro). Lo que me gustaría hacer es enumerar solo los nombres de archivo (no el directorio / ruta), y para complicar más, tengo el mismo nombre de archivo con diferente extensión, así que necesito filtrar el resultado usando -name
y -o
, el problema son las sugerencias que vio usar -printf
o basename
, y esos no funcionan bien cuando hay -name *.txt -o name *.pdf
. ¿Existe alguna otra forma de solucionar este problema?
Ejemplo de mis archivos:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
Solo estoy interesado en enumerar uno o más tipos de archivo por listado (usando -name
para filtrar mis resultados.
¿Es posible lograrlo usando solo 1 find
comando o tengo que hacerlo en 2 pasos (guardar el resultado en un archivo temporal, luego filtrar / eliminar el directorio del archivo temporal)? El resultado que intento lograr es un archivo de texto con nombre de archivo por línea:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
El comando que estaba usando es
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
Estoy usando GNU find.
Actualizar
Resultó que tengo que poner \(...\)
, como lo recordó αғsнιη
Respuestas
Cuando utilice varias expresiones en el modo lógico OR, -o
debe encerrarlas todas dentro \( ... \)
, de lo contrario, siempre se respetará el resultado de la última expresión; y -printf '%f\n'
se utiliza para imprimir el nombre de los archivos solo con los directorios principales eliminados.
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
ver man findbajo OPERADORES sección acerca de ( expr )
:
OPERADORES
...(expr)
Forzar precedencia. Dado que los paréntesis son especiales para el shell, normalmente deberá citarlos.
por lo que puede usar \( ... \)
o '(' ... ')'
(los espacios en blanco después y antes del paréntesis son importantes) para escapar de ellos.
Como ya se ha mencionado, debe agrupar sus -name
pruebas entre paréntesis. Estos paréntesis deben escaparse \( ... \)
o citarse como, por ejemplo, '(' ... ')'
para protegerlos del shell (donde de otro modo designarían un subshell).
Usando estándar find
y también facilitando un poco el manejo de los sufijos de nombre de archivo:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
Esto primero establece los parámetros posicionales en la lista de sufijos de nombre de archivo que nos gustaría ver (esto también podría tomarse de la línea de comando si se trata de un script) y construye la lista OR de -name
pruebas. Luego se usa en la find
línea de comando.
El find
comando en sí llama a la basename
utilidad para cada nombre encontrado.
Como alternativa, podríamos usar una sustitución de parámetros para eliminar todo menos el componente de nombre de archivo de cada nombre de ruta, pero para hacerlo debemos pasar los nombres de ruta a un sh -c
script en línea :
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
Esperaría que esto se ejecute más rápido que la variación que usa basename
, al menos si hay muchos nombres de archivo para manejar, aunque con GNU basename
de coreutils, podría usar -a
o me --multiple
gusta:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
Esto llamaría el basename
menor número de veces posible. Pero, de nuevo, si tenía coreutils instalado, es posible que también tenga findutils, con GNU find
, y podría utilizar -printf '%f\n'
para hacer lo mismo.