¿Cómo usar el comando buscar para listar nombres de archivos pero no rutas?

Jan 06 2021

Revisé algunas respuestas en línea, pero no funcionan cuando hay un -namepará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 -namey -o, el problema son las sugerencias que vio usar -printfo 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 -namepara filtrar mis resultados.

¿Es posible lograrlo usando solo 1 findcomando 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

3 αғsнιη Jan 06 2021 at 21:02

Cuando utilice varias expresiones en el modo lógico OR, -odebe 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.

1 Kusalananda Jan 06 2021 at 22:58

Como ya se ha mencionado, debe agrupar sus -namepruebas 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 findy 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 -namepruebas. Luego se usa en la findlínea de comando.

El findcomando en sí llama a la basenameutilidad 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 -cscript 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 basenamede coreutils, podría usar -ao me --multiplegusta:

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

Esto llamaría el basenamemenor 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.