É muito fácil usar o split()
JavaScript para quebrar uma string em uma matriz.
E o script de shell?
Digamos que eu queira fazer isso:
$ script.sh var1_var2_var3
Quando o usuário fornece essa string var1_var2_var3
para o script.sh, dentro do script ele a converterá em uma matriz como
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
shell
shell-script
string
AGamePlayer
fonte
fonte
shell
você está usando, combash
que você pode fazerIFS='_' read -a array <<< "${string}"
perl
também pode fazer isso. Não é uma concha "pura", mas é bastante comum.Respostas:
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 defor 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
) aglob
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
_
:Para ver a distinção entre separador e delimitador , tente:
Isso o dividirá em
var1
evar2
somente (nenhum elemento extra vazio).Portanto, para torná-lo semelhante ao JavaScript
split()
, você precisará de uma etapa extra:(observe que ele dividiria um elemento vazio
$string
em 1 (não 0 ), como o JavaScriptsplit()
).Para ver a guia de tratamentos especiais, o espaço e a nova linha, compare:
(de onde você chega
var1
evar2
) comonde você começa:
''
,var1
,''
,var2
,''
.Observe que o
zsh
shell não invoca esse operador split + glob implicitamente assim, a menos que seja dentrosh
ouksh
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:ou para preservar os elementos vazios:
Note-se que não
s
é para a divisão , não delimitando (também com$IFS
, um conhecido POSIX não conformidade dozsh
). É 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 naabc
string, enquanto comIFS=abc
, que se dividiria ema
,b
ouc
.Com
zsh
eksh93
, 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 exemploIFS=_; set -f; set -- $@
, não seria equivalente aIFS=_; 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 umsplit
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).O
zsh
shell possui suporte interno para expressões regulares compatíveis com Perl (em seuzsh/pcre
módulo), mas usá-lo para dividir uma string, embora possível seja relativamente complicado.fonte
$PATH
em:
) ao contrário, você geralmente querem preservar os elementos vazios. Observe que no shell Bourne, todos os personagens estavam recebendo o tratamento especial,ksh
alterado para ter apenas os espaços em branco (apenas espaço, guia e nova linha) tratados especialmente.zsh
tratamento com string contendo 2 ou mais caracteres${(s:string:)var}
? Se adicionado, eu posso apagar a minha resposta :)S
representa o separador , não o delimitador . Pelo menos, é o que diz o manual do meu bash.$IFS
vem do shell Bourne onde era separador , o ksh mudou o comportamento sem alterar o nome. Menciono isso para enfatizar quesplit+glob
(exceto em zsh ou pdksh) simplesmente não se divide mais.Sim, use
IFS
e configure-o para_
. Em seguida, useread -a
para armazenar em uma matriz (-r
desativa a expansão da barra invertida). Observe que isso é específico ao bash; O ksh e o zsh possuem recursos semelhantes com sintaxe ligeiramente diferente, e o sh simples não possui variáveis de matriz.A partir de
man bash
:Observe que
read
para na primeira nova linha. Passe-d ''
pararead
evitar isso, mas nesse caso, haverá uma nova linha extra no final devido ao<<<
operador. Você pode removê-lo manualmente:fonte
$r
que não contém caracteres de nova linha ou barras invertidas. Observe também que ele funcionará apenas nas versões recentes dobash
shell.bash
,read -a
foi introduzido no bash 4, certo?<<<
foi adicionado recentemente,bash
mas parece que está lá desde 2.05b (2002).read -a
é ainda mais velho que isso.<<<
vemzsh
e é suportado porksh93
(e mksh e yash) também, masread -a
é específico do bash (está-A
no ksh93, yash e zsh).