A maneira provavelmente mais fácil e segura no BASH 3 e acima é:
var="string to split"
read -ra arr <<<"$var"
(onde arr
é a matriz que pega as partes divididas da sequência) ou, se houver novas linhas na entrada e você desejar mais do que apenas a primeira linha:
var="string to split"
read -ra arr -d '' <<<"$var"
(observe o espaço -d ''
, ele não pode ser deixado de fora), mas isso pode fornecer uma nova linha inesperada de <<<"$var"
(como isso implicitamente adiciona um LF no final).
Exemplo:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Produz o esperado
[*]
[a]
[*]
como esta solução (em contraste com todas as soluções anteriores aqui) não é propensa a globbing inesperado e muitas vezes incontrolável do shell.
Além disso, isso fornece todo o poder do IFS, como você provavelmente deseja:
Exemplo:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Produz algo como:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Como você pode ver, os espaços também podem ser preservados dessa maneira:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
saídas
[ split ]
[ this ]
Observe que a manipulação IFS
no BASH é um assunto por si só, assim como seus testes, alguns tópicos interessantes sobre isso:
unset IFS
: Ignora execuções de SPC, TAB, NL e on-line inicia e termina
IFS=''
: Sem separação de campos, apenas lê tudo
IFS=' '
: Executa o SPC (e somente o SPC)
Algum último exemplo
var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
saídas
1 [this is]
2 [a test]
enquanto
unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
saídas
1 [this]
2 [is]
3 [a]
4 [test]
BTW:
Se você não está acostumado a $'ANSI-ESCAPED-STRING'
se acostumar com isso, economiza tempo.
Se você não incluir -r
(como em read -a arr <<<"$var"
), a leitura será escapada pela barra invertida. Isso é deixado como exercício para o leitor.
Para a segunda pergunta:
Para testar algo em uma string em que costumo me ater case
, já que isso pode verificar vários casos de uma só vez (nota: case apenas executa a primeira correspondência, se você precisar de instruções de uso de multiplicação case
), e essa necessidade costuma ser o caso (trocadilho pretendido):
case "$var" in
'') empty_var;; # variable is empty
*' '*) have_space "$var";; # have SPC
*[[:space:]]*) have_whitespace "$var";; # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";; # non-alphanum-chars found
*[-+.,]*) have_punctuation "$var";; # some punctuation chars found
*) default_case "$var";; # if all above does not match
esac
Portanto, você pode definir o valor de retorno para verificar o SPC assim:
case "$var" in (*' '*) true;; (*) false;; esac
Por que case
? Como geralmente é um pouco mais legível que as sequências de expressões regulares, e graças aos metacaracteres da Shell, ele lida com 99% de todas as necessidades muito bem.