Estoy en un directorio en el que tengo dos archivos de texto:
$ touch test1.txt
$ touch test2.txt
Cuando intento enumerar los archivos (con Bash) usando algún patrón, funciona:
$ ls test?.txt
test1.txt test2.txt
$ ls test{1,2}.txt
test1.txt test2.txt
Sin embargo, cuando un patrón es generado por un comando incluido $(), solo uno de los patrones funciona:
$ ls $(echo 'test?.txt')
test1.txt test2.txt
$ ls $(echo 'test{1,2}.txt')
ls: cannot access test{1,2}.txt: No such file or directory
¿Que está pasando aqui? ¿Por qué el patrón {1,2}no funciona?
bash
bash-expansion
Herosław Miraszewski
fuente
fuente

?está también citado, y consigue expandieron después de$(...)lo sustituye, pero la expansión de llaves no.$-expansions:zsh -o globsubst -c 'a=/e*; b={/b*,/v*}; echo $a; echo $b'.Respuestas:
Es una combinación de dos cosas. Primero, la expansión de llaves no es un patrón que coincida con los nombres de los archivos: es una sustitución puramente textual. Consulte ¿Cuál es la diferencia entre `a [bc] d` (paréntesis) y` a {b, c} d` (llaves)? . En segundo lugar, cuando usa el resultado de una sustitución de comando fuera de las comillas dobles (
ls $(…)), lo que sucede es solo la coincidencia de patrones (y la división de palabras: el operador "split + glob"), no un análisis completo.Con
ls $(echo 'test?.txt'), el comandoecho 'test?.txt'genera la cadenatest?.txt(con una nueva línea final). La sustitución del comando da como resultado la cadenatest?.txt(sin una nueva línea final, porque la sustitución del comando elimina las nuevas líneas finales). Esta sustitución sin comillas se divide en palabras, produciendo una lista que consiste en una sola cadenatest?.txtya que no hay caracteres de espacio en blanco (más precisamente, no hay caracteres$IFS) en ella. Cada elemento de esta lista de un elemento se somete a una expansión de comodín condicional, y dado que hay un carácter comodín?en la cadena, la expansión de comodín ocurre. Dado que el patróntest?.txtcoincide con al menos un nombre de archivo, el elemento de la listatest?.txtse reemplaza por la lista de nombres de archivo que coinciden con los patrones, produciendo la lista de dos elementos que contienetest1.txtytest2.txt. Finalmentelsse llama con dos argumentostest1ytest2.Con
ls $(echo 'test{1,2}'), el comandoecho 'test{1,2}'genera la cadenatest{1,2}(con una nueva línea final). La sustitución del comando da como resultado la cadenatest{1,2}. Esta sustitución sin comillas se divide en palabras, produciendo una lista que consiste en una sola cadenatest{1,2}. Cada elemento de esta lista de un elemento experimenta una expansión de comodín condicional, que no hace nada (el elemento se deja como está) ya que no hay caracteres comodín en la cadena. Asílsse llama con el argumento únicotest{1,2}.A modo de comparación, esto es lo que sucede con
ls $(echo test{1,2}). El comandoecho test{1,2}genera la cadenatest1 test2(con una nueva línea final). La sustitución del comando da como resultado la cadenatest1 test2(sin una nueva línea final). Esta sustitución sin comillas sufre división de palabras, produciendo dos cadenastest1ytest2. Luego, dado que ninguna de las cadenas contiene un carácter comodín, se dejan solas, por lo quelsse llama con dos argumentostest1ytest2.fuente
.txten la segunda explicación.La expansión de llaves no ocurrirá después de la sustitución del comando. Puede usar eval para forzar otra ronda de expansión:
Su resultado es:
fuente
Ese problema es muy específico
bashy es porque decidieronbashseparar la expansión de la llave de la expansión del nombre de archivo (globbing) y realizarla primero, antes de todas las otras expansiones.Desde la página del
bashmanual:En su ejemplo,
bashsolo verá sus llaves después de haber realizado la sustitución del comando (the$(echo ...)), cuando sea demasiado tarde.Esto es diferente de todos los otros shells, que realizan la expansión de llaves justo antes (y algunos incluso como parte de) la expansión del nombre de ruta (globbing). Eso incluye, pero no se limita a,
cshdónde se inventaron las expansiones de llaves.Este último ejemplo es el mismo en
csh,zsh,ksh93,mkshofish.Además, observe que la expansión de llaves como parte de globbing también está disponible a través de la
glob(3)función de biblioteca (al menos en Linux y todos los BSD), y en otras implementaciones independientes (por ejemplo, en perl:)perl -le 'print join " ", <test{1,2}.txt>'.Por qué eso se hizo de manera diferente
bashprobablemente tenga una historia detrás, pero FWIW no pude encontrar ninguna explicación lógica, y encuentro que todas las racionalizaciones post-hoc no son convincentes.fuente
perlsolía invocarcshpara expandir globs, por lo que no es sorprendente que todavía reconozca los mismos operadores de globbing quecshPor favor, inténtalo:::
ls $ (prueba de eco {1,2} \. txt)
Con una barra invertida. Ahora funciona. También elimine lo que decía el cartel anterior, las comillas. El punto no es para un patrón coincidente, sino que debe tomarse literalmente como período aquí.
fuente
{1,2}"se comporta como lo hace? La pregunta no es "¿Cómo puedo usar un comando{1,2}para comportarme de la manera en que?funciona?" Estás respondiendo la pregunta equivocada. (2) La barra invertida no tiene nada que ver con eso. Su comando funciona de la manera en que lo hace porque ha eliminado las comillas que estaban en el comando en la pregunta.Funciona si eliminas las comillas
fuente
?).