Uma variável sem aspas (como em $var
) ou substituição de comando (como em $(cmd)
ou 'cmd'
) é o operador split + glob em shells similares a Bourne.
Ou seja, o conteúdo é dividido de acordo com o valor atual da variável $IFS
special (que, por padrão, contém os caracteres space, tab e newline)
E cada palavra resultante dessa divisão está sujeita a geração de nome de arquivo (também conhecida como globbing ou expansão de nome de arquivo ), ou seja, eles são considerados padrões e são expandidos para a lista de arquivos que correspondem a esse padrão.
Portanto, em for i in $(xrandr)
, o $(xrandr)
, porque não está entre aspas, é dividido em sequências de espaço, tabulação e caracteres de nova linha. E cada palavra resultante dessa divisão é verificada quanto a nomes de arquivos correspondentes (ou deixada como está se eles não corresponderem a nenhum arquivo), e for
faz um loop sobre todos eles.
Em for i in "$(xrandr)"
, não estamos usando o operador split + glob como a substituição do comando é citada, portanto há uma passagem no loop no valor um : a saída de xrandr
(sem os caracteres de nova linha à direita que comandam as tiras de substituição ).
No entanto, em echo $i
, $i
não é citada novamente, novamente o conteúdo de $i
é dividido e sujeito a geração de nome de arquivo e esses são passados como argumentos separados para o echo
comando (e echo
exibe seus argumentos separados por espaços).
Então, lições aprendidas:
- se você não quiser divisão de palavras ou geração de nome de arquivo , sempre cite expansões de variáveis e substituições de comandos
- se você quiser dividir palavras ou geração de nome de arquivo , deixe-as sem aspas, mas defina
$IFS
de 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 pela lista de palavras separadas em branco na saída de xrandr
, será necessário:
- 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 quexrandr
nunca produzirá nenhum caractere*
ou?
ou[
(que são curingas usados nos padrões de geração de nome de arquivo)
E, em seguida, use somente o operador split + glob (somente deixe a substituição do comando ou a expansão variável sem aspas) na parte in
do loop for
:
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
Se você quiser fazer um loop pelas linhas (não vazias) da saída xrandr
, será necessário definir $IFS
como o caractere de nova linha:
IFS='
'