programas - ¿Cómo asignar una expresión glob a una variable en un script Bash?
variables de entorno linux bash (7)
Cuando las siguientes dos líneas de código se ejecutan en un script bash, "ls" se queja de que los archivos no existen:
dirs=/content/{dev01,dev02}
ls -l $dirs
Cuando ejecuto el script con la opción -x, parece que está pasando la variable dentro de comillas simples (lo que evitaría englobar):
+ dirs=/content/{dev01,dev01}
+ ls -l ''/content/{dev01,dev01}''
ls: /content/{dev01,dev01}: No such file or directory
Si ejecuto el comando "ls" desde mi shell interactivo (sin comillas), devuelve los dos directorios.
He estado leyendo el Manual de referencia de Bash (v 3.2) y no veo ninguna razón para que no se produzca el englobado del nombre del archivo (no estoy pasando -f al shell), o cualquier cosa que pueda establecer para garantizar que globbing sucede.
ls `echo $dirs`
funciona bajo cygwin.
Creo que es el orden de las expansiones:
El orden de las expansiones es:
brace expansion
llaves,brace expansion
tilde, expansión devariable
y aritmética de parámetros y sustitución de comandos (hecho de izquierda a derecha), división de palabras ypathname expansion
.
Entonces, si su variable es sustituida, la expansión del corsé ya no tiene lugar. Esto funciona para mí:
eval ls $dirs
Ten mucho cuidado con eval Ejecutará las cosas textualmente. Entonces, si los directorios contienen f{m,k}t*; some_command
f{m,k}t*; some_command
, some_command se ejecutará después de que ls finalice. Ejecutará la cadena que le das a eval
en el shell actual. Pasará /content/dev01 /content/dev02
a ls, ya sea que existan o no. Poner *
después de las cosas lo convierte en una expansión de nombre de ruta, y omitirá las rutas que no existen:
dirs=/content/{dev01,dev02}*
No estoy 100% seguro de esto, pero tiene sentido para mí.
Esto no es englobamiento de nombre de archivo, esta es la expansión de llaves. La diferencia es sutil, pero existe: en el englobado de nombres de archivo, solo recibiría los archivos existentes como resultado, mientras que en la expansión de llaves se puede generar cualquier tipo de cadena.
http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion
http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion
Ahora, esto es lo que funcionó para mí:
#!/bin/sh
dirs=`echo ./{dev01,dev02}`
ls $dirs
Aquí hay una excelente discusión de lo que estás tratando de hacer.
La respuesta corta es que quieres una matriz:
dirs=(/content/{dev01,dev01})
Pero lo que haces con los resultados puede ser más complejo de lo que pretendías, creo.
Como quiera agrupar los archivos, no debe usar expansiones de corchetes. Usar la expansión de la abrazadera en este caso es un antipatrón y definitivamente la herramienta incorrecta para el trabajo.
Lo que quieres es ampliar globbing :
shopt -s extglob # likely already set in interactive shells
dirs=/content/@(dev01|dev02)
ls $dirs
Sospecho que lo que necesitas es una matriz, pero eso te restringirá a ataques más nuevos. Es ahorrar que usar eval.
dirs=( /"content with spaces"/{dev01,dev02} )
dirs=( /content/{dev01,dev02} )
ls -l "${dirs[@]}"
/content/{dev01,dev02}
se expandirá a:
"/content/dev01" "/content/dev02"
La existencia de esos directorios es irrelevante para la expansión.
Se vuelve impredecible cuando asigna una variable a una expansión de llave.
dirs=/content/{dev01,dev02}
puede convertirse en
"/content/dev01"
o
"/content/dev01 /content/dev02"
o
"/content/dev01" "/content/dev02"
o
"/content/{dev01,dev02}"
Si cita las llaves de alguna forma, no se expandirán, por lo que el resultado contendrá las llaves y carecerá de significado.
Para la gente (como yo) encontrar esto a través de Google, las respuestas de @Peter y @feoh son la solución general a "Cómo agrupar variables en script bash".
list_of_results=(pattern)
guardará los nombres de archivos existentes que coincidan con el pattern
en la matriz list_of_results
. Cada elemento de list_of_results
contendrá un nombre de archivo, espacios y todo.
Puede acceder a cada resultado como "${list_of_results[<index>]}"
para <index>
partir de 0. Puede obtener toda la lista, correctamente citada, como "${list_of_results[@]}"
.