Una mejor alternativa.

Una mejor alternativa.

Estoy intentando expandir una cadena que incluye un comodín y una colección de extensiones especificadas entre llaves. Nada parece funcionar como lo ilustra el siguiente ejemplo. la variable firstListse expande bien, pero ninguno de los dos secondList, thirdListo fourthListse expande correctamente. También probé varias versiones evalpero ninguna funciona. Cualquier ayuda sería apreciada

#!/bin/bash
touch a.ext1
touch b.ext1
firstList='*.ext1'
ls  $firstList
touch a.ext2
touch b.ext2
secondList='*.{ext1,ext2}'
ls $secondList 
ls '$secondList'
ls "$secondList"
thirdList=*.{ext1,ext2}
ls $thirdList  
ls '$thirdList'
ls "$thirdList"
fourthList="*.{ext1,ext2}"
ls $fourthList
ls '$fourthList'
ls "$fourthList"

Respuesta1

Elcaparazónse expande *solo si no está entre comillas, cualquier cita detiene la expansión por parte del shell.

Además, una expansión de llave debe estar sin comillas para que el caparazón la expanda.

Este trabajo (usemos echo para ver qué hace el shell):

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Incluso si hay archivos con otros nombres:

$ touch {a,b}.{ext1,ext2} {c,d}.{ext3,ext4} none
ls
a.ext1  a.ext2  b.ext1  b.ext2  c.ext3  c.ext4  d.ext3  d.ext4  none

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

¿Por qué funciona eso?

Es importante que entendamos por qué funciona. Es por el orden de expansión. Primero la "Expansión Brace" y luego (la última) la "Expansión de nombre de ruta" (también conocida como expansión global).

Brace --> Parameter (variable) --> Pathname

Podemos desactivar la "Expansión de nombre de ruta" por un momento:

$ set -f
$ echo *.{ext1,ext2}
*.ext1 *.ext2

La "Expansión del nombre de ruta" recibe dos argumentos: *.ext1y *.ext2.

$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

El problema es que no podemos usar una variable para la expansión de llaves.
Se ha explicado muchas veces antes porusando una variable dentro de una "Expansión de llave"

Para expandir una "Expansión de llave" que es el resultado de una "Expansión de variable", debe volver a enviar la línea de comando al shell con eval.

$ list={ext1,ext2}
$ eval echo '*.'"$list"

Tirante -->Variable--> Globo || -->Abrazadera-->Variables -->globo
........ citado aquí -->^^^^^^ || evaluación ^^^^^^^^^^^^^^^^^^^^^^^^^

Los valores de los nombres de los archivos no generan problemas de ejecución para eval:

$ touch 'a;date;.ext1'
eval echo '*.'"$list"
a;date;.ext1 a.ext1 b.ext1 a.ext2 b.ext2

Pero el valor de $listpodría ser peligroso. Sin embargo, el valor de $listlo establece el guionista. El guionista tiene el control de eval: Simplemente no utilice valores establecidos externamente para $list. Prueba esto:

#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"

Una mejor alternativa.

Una alternativa (sin evaluación) esutilizar Bash "Patrones extendidos":

#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list

Nota: tenga en cuenta que ambas soluciones (eval y patrones) (tal como están escritas) son seguras para nombres de archivos con espacios o líneas nuevas. Pero fallará $listcon espacios, porque $listno está entre comillas o la evaluación elimina las comillas.

Respuesta2

Considerar:

secondList='*.{ext1,ext2}'
ls $secondList 

El problema es eseexpansión de corséestá hechoantes expansión variable. Eso significa que, en lo anterior, nunca se realiza la expansión de la llave.

Esto se debe a que, cuando bash ve por primera vez la línea de comando, no hay llaves. Una vez secondListampliado, ya es demasiado tarde.

Lo siguiente funcionará:

$ s='*'
$ ls $s.{ext1,ext2}
a.ext1  a.ext2  b.ext1  b.ext2

Aquí, la línea de comando tiene llaves para queexpansión de corsépuede realizarse como primer paso. Después de eso, el valor de $sse sustituye en (expansión variable), y por últimoexpansión del nombre de rutaes interpretado.

Documentación

man bashexplica el orden de expansión:

El orden de las expansiones es: expansión de llaves; expansión de tilde, expansión de parámetros y variables, expansión aritmética y sustitución de comandos (realizada de izquierda a derecha); división de palabras; y expansión del nombre de ruta.

información relacionada