Quiero buscar recursivamente cada *.pdfarchivo en un directorio ~/foocuyo nombre base coincida con el nombre del directorio principal del archivo.
Por ejemplo, suponga que la estructura del directorio se ~/foove así
foo
├── dir1
│ ├── dir1.pdf
│ └── dir1.txt
├── dir2
│ ├── dir2.tex
│ └── spam
│ └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf
Ejecutar mi comando deseado volvería
~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
¿Es esto posible usar findo alguna otra utilidad básica? Supongo que esto es factible usando la -regexopción findpero no estoy seguro de cómo escribir el patrón correcto.

Respuestas:
Con GNU
find:-regextype egrepuse la expresión regular de estilo egrep..*/coincidir con las directivas de los abuelos.([^/]+)/hacer coincidir el directorio padre en un grupo.\1\.pdfusebackreferencepara hacer coincidir el nombre del archivo como directorio principal.actualizar
Uno (yo mismo) podría pensar que
.*es lo suficientemente codicioso, no es necesario excluir/de la coincidencia de padres:El comando anterior no funcionará bien, porque coincide
./a/b/a/b.pdf:.*/partidos./(.+)/partidosa/b/\1.pdfpartidosa/b.pdffuente
find . -regex '.*/\([^/]*\)/\1\.pdf'y luego incluso funcionaría con BSDfind.La variante de bucle tradicional de
find .. -exec sh -c ''usar las construcciones de shell para que coincida con el nombre base y la ruta inmediata anterior sería hacer a continuación.Para desglosar las expansiones de parámetros individuales
filecontiene la ruta completa del.pdfarchivo devuelto por elfindcomando"${file##*/}"contiene solo la parte posterior a la última,/es decir, solo el nombre base del archivo"${file%/*}"contiene la ruta hasta el final,/es decir, excepto la parte del nombre base del resultado"${path##*/}"contiene la parte posterior a la última/de lapathvariable, es decir, la ruta de la carpeta inmediata sobre el nombre base del archivo"${base%.*}"contiene la parte del nombre base con la.pdfextensión eliminadaEntonces, si el nombre base sin extensión coincide con el nombre de la carpeta inmediata anterior, imprimimos la ruta.
fuente
El reverso de la respuesta de Inian , es decir, buscar directorios, y luego ver si contienen un archivo con un nombre en particular.
A continuación se imprimen los nombres de ruta de los archivos encontrados en relación con el directorio
foo:${dirpath##*/}será reemplazado por la parte del nombre del archivo de la ruta del directorio, y podría ser reemplazado por$(basename "$dirpath").Para las personas que les gusta la sintaxis de cortocircuito:
El beneficio de hacerlo de esta manera es que puede tener más archivos PDF que directorios. El número de pruebas involucradas se reduce si uno restringe la consulta por un número menor (el número de directorios).
Por ejemplo, si un solo directorio contiene 100 archivos PDF, esto solo intentaría detectar uno de ellos en lugar de probar los nombres de los 100 archivos con respecto al del directorio.
fuente
con
zsh:Tenga en cuenta que si bien
**/no seguirá enlaces simbólicos, lo*/hará.fuente
No se especificó, pero aquí hay una solución sin expresiones regulares si alguien está interesado.
Podemos usar
find . -type fpara obtener archivos, luego utilizardirnameybasenameescribir el condicional. Las utilidades tienen el siguiente comportamiento:basenamedevuelve solo el nombre del archivo después del último/:dirnameda todo el camino hasta la final/:Por lo tanto,
basename $(dirname $file)proporciona el directorio principal del archivo.Solución
Combine lo anterior para formar el condicional
"$(basename $file)" = "$(basename $(dirname $file))".pdf, luego solo imprima cada resultadofindsi ese condicional devuelve verdadero.En el ejemplo anterior, hemos agregado un directorio / archivo con espacios en el nombre para tratar ese caso (gracias a @Kusalananda en los comentarios)
fuente
Final Thesis.pdf(con un espacio).Tomo bash globbing, pruebas simples de bucle sobre cadena cualquier día sobre el programa Find . Llámame irracional, y si bien puede ser subóptimo, un código tan simple me sirve: ¡legible y reutilizable, incluso satisfactorio! Permítanme, por lo tanto, sugerir una combinación de:
• fiesta Globstar :
for f in ** ; do ...** bucles más de todos los archivos en el directorio actual y todas las subcarpetas .. comprobar el estado de Globstar en su sesión actual:shopt -p globstar. Para activar Globstar:shopt -s globstar.• Utilidad "archivo" :
if [[ $(file "$f") =~ pdf ]]; then ...para verificar el formato de archivo real para pdf , más robusto que probar solo para la extensión del archivo• basename, dirname : para comparar el nombre del archivo con el nombre del directorio inmediatamente superior.
basenamedevuelve el nombre del archivo -dirnamedevuelve la ruta completa del directorio - combina las dos funciones para devolver solo el directorio que contiene el archivo correspondiente. Puse cada uno en una variable ( _mydir y _myf ) para luego hacer una prueba simple usando = ~ para la coincidencia de cadenas.Una sutileza: elimine cualquier "punto" en el nombre del archivo para evitar que coincida con el directorio actual cuyo acceso directo también es "." - Utilicé la sustitución directa de cadenas en la variable _myf :
${_myf//./}- no es muy elegante pero funciona. Coincidencias positivas volverán ruta de cada archivo - junto con la ruta completa de la carpeta actual precediendo la salida con:$(pwd)/.Código
fuente