Nas versões antigas, bash
você tinha que citar variáveis depois <<<
. Isso foi corrigido no 4.4. Nas versões anteriores, a variável seria dividida no IFS e as palavras resultantes unidas no espaço antes de serem armazenadas no arquivo temporário que compõe esse <<<
redirecionamento.
No 4.2 e antes, ao redirecionar os componentes internos como read
ou command
, essa divisão levaria o IFS para o componente interno (4.3 corrigiu isso):
$ bash-4.2 -c 'a=a.b.c.d; IFS=. read x <<< $a; echo "$x"'
a b c d
$ bash-4.2 -c 'a=a.b.c.d; IFS=. cat <<< $a'
a.b.c.d
$ bash-4.2 -c 'a=a.b.c.d; IFS=. command cat <<< $a'
a b c d
Essa foi corrigida em 4.3:
$ bash-4.3 -c 'a=a.b.c.d; IFS=. read x <<< $a; echo "$x"'
a.b.c.d
Mas $a
ainda está sujeito à divisão de palavras por lá:
$ bash-4.3 -c 'a=a.b.c.d; IFS=.; read x <<< $a; echo "$x"'
a b c d
No 4.4:
$ bash-4.4 -c 'a=a.b.c.d; IFS=.; read x <<< $a; echo "$x"'
a.b.c.d
Para portabilidade para versões mais antigas, cite sua variável (ou use de zsh
onde ela <<<
vem em primeiro lugar e que não possui esse problema)
$ bash-any-version -c 'a=a.b.c.d; IFS=.; read x <<< "$a"; echo "$x"'
a.b.c.d
Observe que essa abordagem para dividir uma string funciona apenas para strings que não contêm caracteres de nova linha. Observe também que a..b.c.
seria dividida em "a"
, ""
, "b"
, "c"
(sem esvaziar último elemento).
Para dividir seqüências arbitrárias, você pode usar o operador split + glob (o que a tornaria padrão e evitaria armazenar o conteúdo de uma variável em um arquivo temporário da mesma <<<
forma):
var='a.new
line..b.c.'
set -o noglob # disable glob
IFS=.
set -- $var'' # split+glob
for i do
printf 'item: <%s>\n' "$i"
done
ou:
array=($var'') # in shells with array support
O ''
objetivo é preservar um elemento vazio à direita, se houver. Isso também dividiria um vazio $var
em um elemento vazio.
Ou use um shell com um operador de divisão adequado:
zsh
:
array=(${(s:.:)var} # removes empty elements
array=("${(@s:.:)var}") # preserves empty elements
rc
:
array = ``(.){printf %s $var} # removes empty elements
fish
set array (string split . -- $var) # not for multiline $var