Uma variável não citada (como em $var
) ou substituição de comando (como em $(cmd)
ou `cmd`
) é o operador split + glob em shells semelhantes a Bourne.
Ou seja, seu conteúdo é dividido de acordo com o valor atual da $IFS
variável especial (que por padrão contém os caracteres de espaço, tabulação e nova linha)
E então, cada palavra resultante dessa divisão está sujeita à geração do nome do arquivo (também conhecido como globbing ou expansão do nome do arquivo ), ou seja, elas são consideradas como padrões e são expandidas para a lista de arquivos que correspondem a esse padrão.
Assim for i in $(xrandr)
, em , $(xrandr)
porque não está entre aspas, é dividido em seqüências de caracteres de espaço, tabulação e nova linha. E cada palavra resultante dessa divisão é verificada quanto a nomes de arquivos correspondentes (ou deixados como se não correspondam a nenhum arquivo) e for
passa por cima de todos eles.
Em for i in "$(xrandr)"
, não estamos usando o operador split + glob como a substituição de comando é citada; portanto, há uma passagem no loop em um valor: a saída de xrandr
(sem os caracteres de nova linha à direita que comandam as tiras de substituição ).
No entanto echo $i
, em , $i
é sem aspas novamente, portanto, novamente o conteúdo de $i
é dividido e sujeito à geração do nome do arquivo e esses são passados como argumentos separados para o echo
comando (e echo
gera seus argumentos separados por espaços).
Então, lição aprendida:
- se você não deseja dividir palavras ou gerar nome de arquivo , sempre cite expansões variáveis e substituições de comandos
- se você deseja dividir palavras ou gerar nome de arquivo , deixe-os sem aspas, mas defina de
$IFS
acordo e / ou ative ou desative a geração de nome de arquivo, se necessário ( set -f
, set +f
).
Normalmente, no seu exemplo acima, se você quiser fazer um loop sobre a lista de palavras em branco e separadas na saída de xrandr
, precisará:
- deixe
$IFS
em seu valor padrão (ou desative-o) para dividir em espaços em branco
- Use
set -f
para desativar a geração de nome de arquivo, a menos que você tenha certeza de que xrandr
nunca gera nenhum *
ou ?
ou [
caracteres (que são caracteres curinga usados nos padrões de geração de nome de arquivo)
E, em seguida, use apenas o operador split + glob (deixe apenas a substituição de comando ou a expansão variável sem aspas) na in
parte do for
loop:
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
Se você deseja fazer um loop sobre as linhas (não vazias) da xrandr
saída, precisará definir $IFS
o caractere de nova linha:
IFS='
'