bash muda seu comportamento dependendo do valor da variável "IFS"

18

Quando defino a IFSvariável como um espaço, bashtrata vários espaços como um espaço ( myprogramé um programa que imprime os argumentos da linha de comando que recebe):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

Mas quando defino a IFSvariável como vírgula, bashnão trata várias vírgulas como uma vírgula:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world

Por que é que?

user267935
fonte
Apenas para referência, "IFS" significa Separador de Campo Interno .
pr1268

Respostas:

21

Isso está documentado em man bash. Uma única ocorrência de qualquer caractere no IFS que não seja espaço em branco delimita um campo.

De man bash:

O shell trata cada caractere do IFS como um delimitador e divide os resultados das outras expansões em palavras usando esses caracteres como terminadores de campo. Se o IFS estiver desativado ou seu valor for exatamente <space><tab><newline>, o padrão, as seqüências de <space>, <tab>e <newline>no início e no final dos resultados das expansões anteriores serão ignoradas e qualquer sequência de caracteres do IFS que não esteja no início ou no final serve para delimitar palavras. Se o IFS tiver um valor diferente do padrão, as seqüências dos caracteres de espaço em branco espaço, tabulação e nova linha serão ignoradas no início e no final da palavra, desde que o caractere de espaço em branco esteja no valor do IFS (um caractere de espaço em branco do IFS ) Qualquer caractere no IFS que não seja o espaço em branco do IFS, juntamente com qualquer caractere de espaço em branco do IFS adjacente, delimita um campo. Uma sequência de caracteres de espaço em branco do IFS também é tratada como um delimitador. Se o valor do IFS for nulo, nenhuma divisão de palavras ocorrerá. [Enfase adicionada.]

Exemplos: divisão de campo

Se o IFS não tiver caracteres de espaço em branco, o espaço em branco será incluído nos campos:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>

Se o IFS tiver espaços em branco e uma vírgula, as sequências de espaços em branco, seguidas por uma vírgula, seguidas por sequências de espaços em branco, serão tratadas como um único delimitador:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>

Sequências de vírgulas são interpretadas como sequências de campos vazios:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>

Exemplos: espaço em branco à esquerda e à direita

Se o IFS não contiver espaços em branco, os espaços em branco à esquerda e à direita serão mantidos nos campos:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >

Se o IFS contiver espaços em branco, as seqüências iniciais ou finais de espaços em branco serão removidas:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>
John1024
fonte
talvez também deva ser enfatizado "as seqüências dos caracteres de espaço em branco espaço, tabulação e nova linha são ignoradas no início e no final da palavra, desde que o caractere de espaço em branco tenha o valor do IFS"
Jeff Schaller
@JeffSchaller Excelente ideia: acabei de adicionar uma seção sobre isso.
John1024
e se você tiver um arquivo separado por tabulação com alguns valores ausentes? ou seja, você não deseja que sequências de guias sejam tratadas como uma única guia. Além disso, os campos contêm vírgulas; portanto, não é possível usá-lo como delimitador. A única solução é usar outro delimitador (não as guias)?
Davos
@Davos Para dados com cada campo delimitado por uma única guia, pode ser mais natural usar outras ferramentas que lidam com isso facilmente, como awkcom a -F'\t'opção ou cut. Como alternativa, se você possui uma versão recente bash, poderá analisar os campos usando readarraya -d$'\t'opção
precisa saber é o seguinte