for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor 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
$IFSen 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
$IFSen su valor predeterminado (o desactívelo) para dividir en espacios en blanco - Utilice
set -fpara deshabilitar la generación de nombres de archivo a menos que esté seguro de quexrandrnunca 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='
'