¿Cómo escribo un script bash que atraviesa cada directorio dentro de un directorio parent_directory y ejecuta un comando en cada directorio ?
La estructura del directorio es la siguiente:
parent_directory (el nombre puede ser cualquier cosa, no sigue un patrón)
- 001 (los nombres de directorio siguen este patrón)
- 0001.txt (los nombres de archivo siguen este patrón)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
El número de directorios es desconocido.
cd "$d"
sería mejor ya que se transfiere a situaciones en las que el comodín coincide con los archivos cuyos nombres contienen espacios en blanco y / o metacaracteres de shell.for f in foo bar; do cat "$f"/*.txt; done >output
es funcionalmente equivalente acat foo/*.txt bar/*.txt >output
. Sin embargo,ls
es un comando que produce resultados ligeramente diferentes dependiendo de cómo le pase los argumentos; Del mismo modo, ungrep
owc
que genera un nombre de archivo relativo será diferente si lo ejecuta desde un subdirectorio (pero a menudo, desea evitar entrar en un subdirectorio precisamente por esa razón).Esta respuesta publicada por Todd me ayudó.
El
\( ! -name . \)
evita ejecutar el comando en el directorio actual.fuente
find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
-exec bash -c 'cd "$0" && pwd' {} \;
ya que algunos directorios contenían comillas simples y algunas comillas dobles.-mindepth 1
pwd
directamente?disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}
no trabajo.Si está utilizando GNU
find
, puede probar el-execdir
parámetro, por ejemplo:o (según el comentario de @gniourf_gniourf ):
Nota: Puede usar en
${0#./}
lugar de$0
arreglar./
en el frente.o un ejemplo más práctico:
Si desea incluir el directorio actual, es aún más simple usando
-exec
:o usando
xargs
:O ejemplo similar sugerido por @gniourf_gniourf :
Los ejemplos anteriores admiten directorios con espacios en su nombre.
O asignando a bash array:
Cambie
.
a su nombre de carpeta específico. Si no necesita ejecutar recursivamente, puede usar: en sudirs=(*)
lugar. El ejemplo anterior no admite directorios con espacios en el nombre.Entonces, como sugirió @gniourf_gniourf , la única forma adecuada de colocar la salida de find en una matriz sin usar un bucle explícito estará disponible en Bash 4.4 con:
O no es una forma recomendada (que implica el análisis de
ls
):El ejemplo anterior ignoraría el directorio actual (según lo solicitado por OP), pero se romperá en los nombres con los espacios.
Ver también:
fuente
find
en una matriz sin usar un bucle explícito estará disponible en Bash 4.4 conmapfile -t -d '' dirs < <(find . -type d -print0)
. Hasta entonces, su única opción es usar un bucle (o diferir la operaciónfind
).dirs
matriz; usted podría bucle defind
salida 's (con seguridad), así:find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
.IFS
,read
, da la impresión de una complejidad adicional. Tendré que pensarlo, tal vez haya una forma más fácil de hacerlo.IFS
yread
(como dices) se convierte en una segunda naturaleza a medida que te acostumbras ... son parte de las formas canónicas e idiomáticas de escribir guiones.find . -type d -execdir echo $(pwd)/{} ';'
no hace lo que quiere (el$(pwd)
se expande antesfind
incluso se ejecuta) ...Puede lograr esto canalizando y luego utilizando
xargs
. El problema es que necesita utilizar el-I
indicador que sustituirá a la subcadena en su comando de fiesta con la subcadena aprobada por cada uno de losxargs
.Es posible que desee reemplazar
pwd
con cualquier comando que desee ejecutar en cada directorio.fuente
Si se conoce la carpeta de nivel superior, puede escribir algo como esto:
En el $ (JUEGA TANTO COMO QUIERAS); puedes poner tanto código como quieras.
Tenga en cuenta que no "cd" en ningún directorio.
Salud,
fuente
ls
" ; en su lugar, podría hacerlofor dir in $YOUR_TOP_LEVEL_FOLDER/*
.ls $dir
expresiónfuente
Si bien uno de los revestimientos es bueno para un uso rápido y sucio, prefiero a continuación una versión más detallada para escribir scripts. Esta es la plantilla que uso, que se encarga de muchos casos extremos y le permite escribir código más complejo para ejecutar en una carpeta. Puede escribir su código bash en la función dir_command. A continuación, dir_coomand implementa el etiquetado de cada repositorio en git como ejemplo. El resto del script llama a dir_command para cada carpeta en el directorio. También se incluye el ejemplo de iterar solo a través de un conjunto de carpetas determinado.
fuente
No entiendo el formato del archivo, ya que solo quieres recorrer las carpetas ... ¿Estás buscando algo como esto?
fuente
puedes usar
para buscar todos los archivos / directorios en el directorio actual recurrente
De lo que puede canalizar la salida, el comando xargs así
fuente
fuente
cd
en una subshell.cd
por lo que este código en realidad no hace nada útil.