Parece que a prática normal colocaria a configuração do IFS fora do loop while, a fim de não repeti-la para cada iteração ... Esse é apenas um estilo habitual de "macaco vê, macaco faz", como foi para esse macaco até Eu li, homem leu , ou estou perdendo alguma armadilha sutil (ou descaradamente óbvia) aqui?
81
while IFS=X read
não dividir aX
, maswhile IFS=X; read
faz ...while
não faz muito sentido - a condição parawhile
fins naquele ponto e vírgula, então não há nenhum laço real ...read
se torna apenas o primeiro comando dentro do loop de um elemento ... ou não ? E odo
então ..?while
condição (antesdo
).IFS=
o trabalho, masIFS=X
não ... (ou talvez eu tenha uma overdose sobre isso por um tempo .. coffee break necessário :)Vejamos um exemplo, com algum texto de entrada cuidadosamente criado:
São duas linhas, a primeira começando com um espaço e terminando com uma barra invertida. Primeiro, vamos ver o que acontece sem nenhuma precaução
read
(mas usandoprintf '%s\n' "$text"
para imprimir com cuidado,$text
sem nenhum risco de expansão). (Abaixo,$
está o prompt do shell.)read
comeu as barras invertidas: a barra invertida-nova faz com que a nova linha seja ignorada e a barra invertida-qualquer coisa ignora a primeira barra invertida. Para evitar que as barras invertidas sejam tratadas especialmente, usamosread -r
.É melhor, temos duas linhas como esperado. As duas linhas quase contêm o conteúdo desejado: o espaço duplo entre
hello
eworld
foi retido, porque está dentro daline
variável. Por outro lado, o espaço inicial foi consumido. Issoread
ocorre porque lê quantas palavras você passar pelas variáveis, exceto que a última variável contém o restante da linha - mas ainda começa com a primeira palavra, ou seja, os espaços iniciais são descartados.Portanto, para ler cada linha literalmente, precisamos garantir que não haja divisão de palavras . Fazemos isso definindo a
IFS
variável como um valor vazio.Observe como configuramos
IFS
especificamente para a duração doread
built-in . OsIFS= read -r line
conjuntos do ambiente variávelIFS
(para um valor vazio) especificamente para a execução deread
. Essa é uma instância da sintaxe geral de comando simples : uma sequência (possivelmente vazia) de atribuições de variáveis seguida por um nome de comando e seus argumentos (também é possível ativar redirecionamentos a qualquer momento). Comoread
é um built-in, a variável nunca acaba realmente no ambiente de um processo externo; no entanto, o valor de$IFS
é o que estamos atribuindo lá enquantoread
estiver executando is. Observe queread
não é um built-in especial ; portanto, a atribuição dura apenas por sua duração.Portanto, tomamos o cuidado de não alterar o valor de
IFS
outras instruções que possam depender dele. Esse código funcionará independentemente do que o código circundante tenha definidoIFS
inicialmente e não causará nenhum problema se o código dentro do loop dependerIFS
.Contraste com esse trecho de código, que procura arquivos em um caminho separado por dois pontos. A lista de nomes de arquivos é lida de um arquivo, um nome de arquivo por linha.
Se o loop fosse
while IFS=; read -r name; do …
,for dir in $PATH
não seria dividido$PATH
em componentes separados por dois pontos. Se o código fosseIFS=; while read …
, seria ainda mais óbvio queIFS
não está definido:
no corpo do loop.Obviamente, seria possível restaurar o valor
IFS
após a execuçãoread
. Mas isso exigiria conhecer o valor anterior, que é um esforço extra.IFS= read
é a maneira mais simples (e, convenientemente, também a mais curta).¹ E, se
read
for interrompido por um sinal interceptado, possivelmente enquanto o interceptador estiver em execução - isso não é especificado pelo POSIX e depende, na prática, do shell.fonte
while IFS= read
(sem ponto e vírgula depois=
) não é uma forma especial dewhile
ou deIFS
ou deread
.. O construto é genérico: ie.anyvar=anyvalue anycommand
. A falta de;
configuração posterioranyvar
torna o escopo deanyvar
local comoanycommand
.. O loop while - do / done não é 100% relacionado ao escopo local deany_var
.Além da (já clarificada)
IFS
Diferenças de escopo entre owhile IFS='' read
,IFS=''; while read
ewhile IFS=''; read
expressões idiomáticas (per-comando vs script / wide-shellIFS
escopo de variáveis), a lição para levar para casa é que você perde os líderes e espaços à direita de uma linha de entrada se a variável IFS está definido como (contém um) espaço.Isso pode ter consequências bastante graves se os caminhos do arquivo estiverem sendo processados.
Portanto, definir a variável IFS para a sequência vazia é apenas uma má idéia, pois garante que o espaço em branco à esquerda e à direita de uma linha não seja removido.
Veja também: Bash, leia linha por linha do arquivo, com IFS
fonte
Inspirado pela resposta de Yuzem
Se você deseja definir
IFS
um caractere real, funcionou para mimfonte