for i in $(xrandr); do echo "$i" ; done
for i in "$(xrandr)"; do echo "$i"; done
for i in "$(xrandr)"; do echo $i; done
Entiendo por qué 1 difiere de 2. Pero, ¿por qué 3 da un resultado diferente de 2? Por favor explique la salida también. ¿Cómo funcionan las comillas en las líneas nuevas?
Respuesta aceptada:
Una variable sin comillas (como en $var
) o sustitución de comandos (como en $(cmd)
o `cmd`
) es el split+glob operador en shells tipo Bourne.
Es decir, su contenido se divide según el valor actual de $IFS
variable especial (que por defecto contiene los caracteres de espacio, tabulación y nueva línea)
Y luego, cada palabra resultante de esa división está sujeta a generación de nombre de archivo (también conocido como globbing o expansión de nombre de archivo ), es decir, se consideran patrones y se expanden a la lista de archivos que coinciden con ese patrón.
Entonces en for i in $(xrandr)
, el $(xrandr)
, debido a que no está entre comillas, se divide en secuencias de espacios, tabuladores y caracteres de nueva línea. Y cada palabra resultante de esa división se verifica para buscar nombres de archivos coincidentes (o se deja como está si no coinciden con ningún archivo), y for
recorre todos ellos.
En for i in "$(xrandr)"
, no estamos usando el operador split+glob como sustitución de comando se cita, por lo que hay un paso en el bucle en uno valor:la salida de xrandr
(sin los caracteres de nueva línea finales que comandan la sustitución tiras).
Sin embargo, en echo $i
, $i
no está entre comillas nuevamente, por lo que nuevamente el contenido de $i
está dividido y sujeto a generación de nombre de archivo y esos se pasan como argumentos separados al echo
comando (y echo
genera sus argumentos separados por espacios).
Así que lección aprendida:
- si no desea división de palabras o generación de nombre de archivo , siempre cite expansiones de variables y sustituciones de comandos
- si desea división de palabras o generación de nombre de archivo , déjelos sin comillas pero establezca
$IFS
en consecuencia y/o habilite o deshabilite la generación de nombres de archivo si es necesario (set -f
,set +f
).
Por lo general, en su ejemplo anterior, si desea recorrer la lista de palabras separadas en blanco en la salida de xrandr
, necesitarías:
- dejar
$IFS
en su valor predeterminado (o desactívelo) para dividir en espacios en blanco - Utilice
set -f
para deshabilitar la generación de nombres de archivo a menos que esté seguro de quexrandr
nunca genera ningún*
o?
o[
caracteres (que son comodines utilizados en los patrones de generación de nombres de archivo)
Y luego solo use el operador split+glob (solo deje la sustitución de comando o la expansión variable sin comillas) en in
parte del for
bucle:
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
Si desea recorrer las líneas (no vacías) del xrandr
salida, necesitaría configurar $IFS
al carácter de nueva línea:
IFS='
'