La solución más simple es hacer una matriz de los argumentos entre comillas que luego puede repetir si lo desea o pasar directamente a un comando.
eval "array=($string)"
for arg in "${array[@]}"; do echo "$arg"; done
PD. Comente si encuentra una forma más sencilla sin eval
.
Editar:
Sobre la base de la respuesta de @Hubbitus, tenemos una versión completamente desinfectada y citada correctamente. Nota:esto es excesivo y en realidad dejará barras diagonales inversas adicionales en las secciones con comillas simples o dobles que preceden a la mayoría de los signos de puntuación, pero es invulnerable a los ataques.
declare -a "array=($( echo "$string" | sed 's/[][`[email protected]#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
Dejo al lector interesado que modifique como mejor le parezca http://ideone.com/FUTHhj
Cuando vi la respuesta de David Postill, pensé "debe haber una solución más simple". Después de algunos experimentos encontré los siguientes trabajos:-
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo $string
eval 'for word in '$string'; do echo $word; done'
Esto funciona porque eval
expande la línea (eliminando las comillas y expandiendo string
) antes de ejecutar la línea resultante (que es la respuesta en línea):
for word in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $word; done
Una alternativa que se expande a la misma línea es:
eval "for word in $string; do echo \$word; done"
Aquí string
se expande entre comillas dobles, pero el $
debe escaparse para que word
no se expande antes de que se ejecute la línea (en la otra forma, el uso de comillas simples tiene el mismo efecto). Los resultados son:-
[~/]$ 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
¿Cómo hago eso?
$ for l in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $l; done
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
¿Qué hago si mi cadena está en un bash
? variable?
El enfoque simple de usar el bash
el tokenizador de cadenas no funcionará, ya que se divide en todos los espacios, no solo en los que están fuera de las comillas:
[email protected] /f/test
$ cat ./test.sh
#! /bin/bash
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
for word in $string; do echo "$word"; done
[email protected] /f/test
$ ./test.sh
"aString
that
may
haveSpaces
IN
IT"
bar
foo
"bamboo"
"bam
boo"
Para evitar esto, el siguiente script de shell (splitstring.sh) muestra un enfoque:
#! /bin/bash
string=$(cat <<'EOF'
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
EOF
)
echo Source String: "$string"
results=()
result=''
inside=''
for (( i=0 ; i<${#string} ; i++ )) ; do
char=${string:i:1}
if [[ $inside ]] ; then
if [[ $char == \\ ]] ; then
if [[ $inside=='"' && ${string:i+1:1} == '"' ]] ; then
let i++
char=$inside
fi
elif [[ $char == $inside ]] ; then
inside=''
fi
else
if [[ $char == ["'"'"'] ]] ; then
inside=$char
elif [[ $char == ' ' ]] ; then
char=''
results+=("$result")
result=''
fi
fi
result+=$char
done
if [[ $inside ]] ; then
echo Error parsing "$result"
exit 1
fi
echo "Output strings:"
for r in "${results[@]}" ; do
echo "$r" | sed "s/\"//g"
done
Salida:
$ ./splitstring.sh
Source String: "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
Output strings:
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Fuente:Respuesta de StackOverflow Dividir una cadena solo por espacios que están fuera de las comillas de choroba. Se ha modificado el guión para que coincida con los requisitos de la pregunta.