Eu tenho uma string assim:
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
Eu quero ser capaz de dividir assim:
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Como faço isso? (de preferência usando uma linha)
Responder1
Quando vi a resposta de David Postill, pensei “deve haver uma solução mais simples”. Depois de algumas experiências, encontrei os seguintes trabalhos: -
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo $string
eval 'for word in '$string'; do echo $word; done'
Isso funciona porque eval
expande a linha (removendo as aspas e expandindo string
) antes de executar a linha resultante (que é a resposta in-line):
for word in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $word; done
Uma alternativa que se expande para a mesma linha é:
eval "for word in $string; do echo \$word; done"
Aqui string
é expandido entre aspas duplas, mas deve $
ser escapado para que word
in não seja expandido antes da linha ser executada (na outra forma, o uso de aspas simples tem o mesmo efeito). Os resultados são: -
[~/]$ string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
[~/]$ echo $string
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
[~/]$ eval 'for word in '$string'; do echo $word; done'
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
[~/]$ eval "for word in $string; do echo \$word; done"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Responder2
A solução mais simples é criar uma matriz dos argumentos citados, que você pode fazer um loop, se desejar, ou passar diretamente para um comando.
eval "array=($string)"
for arg in "${array[@]}"; do echo "$arg"; done
ps Por favor, comente se você encontrar uma maneira mais simples sem eval
.
Editar:
Com base na resposta do @Hubbitus, temos uma versão totalmente higienizada e devidamente citada. Nota: isso é um exagero e, na verdade, deixará barras invertidas adicionais nas seções com aspas duplas ou simples que precedem a maior parte da pontuação, mas é invulnerável a ataques.
declare -a "array=($( echo "$string" | sed 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
Deixo ao leitor interessado modificar como achar melhorhttp://ideone.com/FUTHhj
Responder3
Parece que xargs pode fazer isso muito bem:
$ a='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
$ printf "%s" "$a" | xargs -n 1 printf "%s\n"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Responder4
Você pode fazer isso com declare
em vez de eval
, por exemplo:
Em vez de:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo "Initial string: $string"
eval 'for word in '$string'; do echo $word; done'
Fazer:
declare -a "array=($string)"
for item in "${array[@]}"; do echo "[$item]"; done
Mas observe que não é muito mais seguro se a entrada vier do usuário!
Então, se você tentar dizer uma string como:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
Você é hostname
avaliado (é claro que pode haver algo como rm -rf /
)!
Uma tentativa muito simples de protegê-lo, basta substituir caracteres como backtrick ` e $:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
declare -a "array=( $(echo $string | tr '`$<>' '????') )"
for item in "${array[@]}"; do echo "[$item]"; done
Agora você obteve uma saída como:
[aString that may haveSpaces IN IT]
[bar]
[foo]
[bamboo]
[bam boo]
[?hostname?]
Mais detalhes sobre métodos e prós e contras você pode encontrar nessa boa resposta:https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead/17529221#17529221
Mas ainda restava vetor para ataque. Eu quero muito ter no método bash de citação de string como entre aspas duplas (") mas sem interpretar o conteúdo.