Quiero actuar en una lista de subdirectorios en un directorio. Considerar:
for x in x86-headers/*/C/populate.sh; do echo $x; done
Esto da
x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh
Pero quiero valores que corresponde a la segunda parte de la ruta,
elf
, gl
, etc. Sé cómo quitarse el principal x86-headers
.
for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done
lo que da
elf/C/populate.sh
gl/C/populate.sh
gmp/C/populate.sh
gnome2/C/populate.sh
gtk2/C/populate.sh
jni/C/populate.sh
libc/C/populate.sh
También sé cómo quitar los términos posteriores en el camino. Es decir, bajando un nivel:
cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done
da
elf
gl
gmp
gnome2
gtk2
jni
libc
Pero, tratar de combinar estos no funciona. Es decir
for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
da
bash: ${${x##x86-headers}%%/*}: bad substitution
Sin duda, esta es una sintaxis incorrecta, pero no sé la sintaxis correcta. Por supuesto, podría haber mejores formas de hacer esto. Si usara Python, usaría dividir /
para dividir cada ruta en una lista y luego elegir el segundo elemento, pero no sé cómo hacerlo en bash.
EDITAR: Gracias por las respuestas. También debería haber preguntado, ¿es posible hacer esto de forma portátil, y si es así, cómo?
i=${x#*/}; i=${i%%/*}
es opcional, ¿verdad?ash
/dash
ejecutarían las asignaciones de derecha a izquierda (que era cómo se comportaba el shell Bourne) y causan problemas en este caso.La expansión de parámetros no le permite anidar expresiones, por lo que se ve obligado a hacerlo en dos pasos, con una asignación:
Tienes la opción de usar matrices aquí, pero creo que sería más engorroso que el PE anterior:
Luego está la tercera opción de usar comandos externos. Con una lista corta de archivos, esta suele ser la opción menos eficiente, pero escalará mejor a medida que aumente la cantidad de archivos:
fuente
zsh
permite el anidamiento.bash
.fuente
Tenga mucho cuidado al usar una construcción como se muestra a continuación:
Como podrás terminar haciendo un
echo *
. En este caso, solo es divertido, ¡pero podría ser mucho peor si eres root, yourCWD
is/
y quieres eliminar algunos subdirectorios en/tmp
lugar de repetirlos!Para arreglar eso en bash, puedes hacer:
Observe
shopt -u nullglob
al final para restaurar el comportamiento predeterminado de bash después del ciclo.Una solución más portátil podría ser:
(Las sustituciones
##
y los%%
parámetros son válidos en ksh88 ).Siga este enlace para una discusión más completa de nullglob .
Observe que las 3 soluciones anteriores fallan si tiene un directorio intermediario con un espacio en su nombre. Para resolverlo, use comillas dobles en la sustitución de variables:
fuente
Para hacer una coincidencia de patrones en los nombres de ruta de forma portátil, puede configurar la
IFS
variable de shell/
y luego usar la expansión de parámetros de shell.¡Hacer todo esto en un subshell ayuda a mantener el entorno del shell principal sin cambios!
fuente