Os shells Bourne / POSIX têm um operador split + glob e é chamado toda vez que você deixa uma expansão de parâmetro ( $var
, $-
...), substituição de comando ( $(...)
) ou expansão aritmética ( $((...))
) sem aspas no contexto da lista.
Na verdade, você invocado por engano quando você fez for name in ${array[@]}
em vez de for name in "${array[@]}"
. (Na verdade, você deve se lembrar de que invocar esse operador assim por engano é fonte de muitos bugs e vulnerabilidades de segurança ).
Esse operador está configurado com o $IFS
parâmetro especial (para informar em quais caracteres dividir (embora tenha cuidado com o espaço, a guia e a nova linha receberem um tratamento especial)) e a -f
opção de desativar ( set -f
) ou ativar ( set +f
) a glob
peça.
Observe também que, enquanto o S
in $IFS
foi originalmente (no shell Bourne de onde $IFS
vem) para Separator, nos shells POSIX, os caracteres em $IFS
devem ser vistos como delimitadores ou terminadores (veja um exemplo abaixo).
Então, para dividir _
:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Para ver a distinção entre separador e delimitador , tente:
string='var1_var2_'
Isso o dividirá em var1
e var2
somente (nenhum elemento extra vazio).
Portanto, para torná-lo semelhante ao JavaScript split()
, você precisará de uma etapa extra:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(observe que ele dividiria um elemento vazio $string
em 1 (não 0 ), como o JavaScript split()
).
Para ver a guia de tratamentos especiais, o espaço e a nova linha, compare:
IFS=' '; string=' var1 var2 '
(de onde você chega var1
e var2
) com
IFS='_'; string='_var1__var2__'
onde você começa: ''
, var1
, ''
, var2
, ''
.
Observe que o zsh
shell não invoca esse operador split + glob implicitamente assim, a menos que seja dentro sh
ou ksh
emulado. Lá, você deve invocá-lo explicitamente. $=string
para a parte dividida, $~string
para a parte global ( $=~string
para ambos) e também possui um operador de divisão onde é possível especificar o separador:
array=(${(s:_:)string})
ou para preservar os elementos vazios:
array=("${(@s:_:)string}")
Note-se que não s
é para a divisão , não delimitando (também com $IFS
, um conhecido POSIX não conformidade do zsh
). É diferente do JavaScript, split()
pois uma string vazia é dividida em 0 (não 1) elemento.
Uma diferença notável com $IFS
-splitting é que se ${(s:abc:)string}
divide na abc
string, enquanto com IFS=abc
, que se dividiria em a
, b
ou c
.
Com zsh
e ksh93
, o tratamento especial que o espaço, a guia ou a nova linha recebe pode ser removido dobrando-os $IFS
.
Como uma nota histórica, a concha Bourne (o ancestral ou conchas POSIX modernas) sempre retirava os elementos vazios. Ele também teve vários bugs relacionados à divisão e expansão de $ @ com valores não padrão de $IFS
. Por exemplo IFS=_; set -f; set -- $@
, não seria equivalente a IFS=_; set -f; set -- $1 $2 $3...
.
Divisão em regexps
Agora, para algo mais próximo do JavaScript split()
que possa ser dividido em expressões regulares, você precisará confiar em utilitários externos.
No baú da ferramenta POSIX, awk
existe um split
operador que pode ser dividido em expressões regulares estendidas (essas são mais ou menos um subconjunto das expressões regulares do tipo Perl suportadas pelo JavaScript).
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
O zsh
shell possui suporte interno para expressões regulares compatíveis com Perl (em seu zsh/pcre
módulo), mas usá-lo para dividir uma string, embora possível seja relativamente complicado.
shell
você está usando, combash
que você pode fazerIFS='_' read -a array <<< "${string}"