La forma probablemente más fácil y segura en BASH 3 y superior es:
var="string to split"
read -ra arr <<<"$var"
(donde arr
está la matriz que toma las partes divididas de la cadena) o, si puede haber nuevas líneas en la entrada y desea más que solo la primera línea:
var="string to split"
read -ra arr -d '' <<<"$var"
(tenga en cuenta el espacio adentro -d ''
, no se puede dejar de lado), pero esto podría darle una nueva línea inesperada <<<"$var"
(ya que esto agrega implícitamente un LF al final).
Ejemplo:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Salidas de lo esperado
[*]
[a]
[*]
ya que esta solución (en contraste con todas las soluciones anteriores aquí) no es propensa a un bloqueo inesperado y, a menudo, incontrolable.
Además, esto le brinda todo el poder de IFS como probablemente desee:
Ejemplo:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Produce algo como:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Como puede ver, los espacios también se pueden preservar de esta manera:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
salidas
[ split ]
[ this ]
Tenga en cuenta que el manejo de IFS
en BASH es un tema en sí mismo, así que haga sus pruebas, algunos temas interesantes sobre esto:
unset IFS
: Ignora ejecuciones de SPC, TAB, NL y en línea comienza y termina
IFS=''
: Sin separación de campo, solo lee todo
IFS=' '
: Ejecuciones de SPC (y solo SPC)
Algun ultimo ejemplo
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
salidas
1 [this is]
2 [a test]
mientras
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
salidas
1 [this]
2 [is]
3 [a]
4 [test]
Por cierto:
Si no estás acostumbrado $'ANSI-ESCAPED-STRING'
, es un ahorro de tiempo.
Si no incluye -r
(como en read -a arr <<<"$var"
), la lectura hace que la barra invertida se escape. Esto se deja como ejercicio para el lector.
Para la segunda pregunta:
Para probar algo en una cadena, generalmente me quedo case
, ya que esto puede verificar si hay varios casos a la vez (nota: el caso solo ejecuta la primera coincidencia, si necesita fallos, use case
declaraciones multiplce ), y esta necesidad suele ser el caso (juego de palabras destinado a):
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
Por lo tanto, puede establecer el valor de retorno para verificar SPC de esta manera:
case "$var" in (*' '*) true;; (*) false;; esac
¿Por qué case
? Debido a que generalmente es un poco más legible que las secuencias de expresiones regulares, y gracias a los metacaracteres de Shell, maneja muy bien el 99% de todas las necesidades.