script programas pasar parametros operaciones manejo entorno ejemplos cadenas aritmeticas bash glob

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 de variable y aritmética de parámetros y sustitución de comandos (hecho de izquierda a derecha), división de palabras y pathname 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[@]}" .