Tengo una cadena que contiene muchas palabras con al menos un espacio entre cada dos. ¿Cómo puedo dividir la cadena en palabras individuales para poder recorrerlas?
La cadena se pasa como un argumento. Ej. ${2} == "cat cat file"
. ¿Cómo puedo recorrerlo?
Además, ¿cómo puedo verificar si una cadena contiene espacios?
¿Intentó simplemente pasar la variable de cadena a un ciclo for
? Bash, por ejemplo, se dividirá en espacios en blanco automáticamente.
sentence="This is a sentence." for word in $sentence do echo $word done
This is a sentence.
Me gusta la conversión a una matriz, para poder acceder a elementos individuales:
sentence="this is a story" stringarray=($sentence)
ahora puede acceder a elementos individuales directamente (comienza con 0):
echo ${stringarray[0]}
o convertir de nuevo a cadena para hacer un ciclo:
for i in "${stringarray[@]}" do : # do whatever on $i done
Por supuesto, el bucle de la cadena directamente fue respondido antes, pero esa respuesta tenía la desventaja de no realizar un seguimiento de los elementos individuales para su uso posterior:
for i in $sentence do : # do whatever on $i done
Consulte también Bash Array Reference
Simplemente use el “set” de proyectiles incorporado. Por ejemplo,
establecer $ text
Después de eso, las palabras individuales en $ text estarán en $ 1, $ 2, $ 3, etc. Para la solidez, uno usualmente lo hace
establecer - texto $ basura cambio
para manejar el caso donde $ text está vacío o comienza con un guión. Por ejemplo:
text = "Esta es una prueba" establecer - texto $ basura cambio por palabra; hacer echo "[$ word]" hecho
Esto imprime
[Esta] [es] [un] [prueba]
La forma más fácil y segura de BASH 3 y superior es:
var="string to split" read -ra arr <<<"$var"
(donde arr
es la matriz que toma las partes divididas de la cadena) o, si puede haber nuevas líneas en la entrada y desea algo más que la primera línea:
var="string to split" read -ra arr -d '' <<<"$var"
(tenga en cuenta el espacio en -d ''
, no puede dejarse de lado), pero esto podría darle una nueva línea inesperada de <<<"$var"
(ya que esto agrega implícitamente una LF al final).
Ejemplo:
touch NOPE var="* a *" read -ra arr <<<"$var" for a in "${arr[@]}"; do echo "[$a]"; done
Resultados lo esperado
[*] [a] [*]
ya que esta solución (a diferencia de todas las soluciones anteriores aquí) no es propensa a englobamiento de shell inesperado ya menudo incontrolable.
También esto le da el poder completo de IFS como probablemente quiera:
Ejemplo:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd) for a in "${arr[@]}"; do echo "[$a]"; done
Resultados algo como:
[tino] [x] [1000] [1000] [Valentin Hilbig] [/home/tino] [/bin/bash]
Como puede ver, los espacios se pueden preservar de esta manera también:
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 por sí mismo, así que haga sus pruebas, algunos temas interesantes sobre esto:
unset IFS
: Ignora las ejecuciones de SPC, TAB, NL y en línea comienza y termina IFS=''
: Sin separación de campo, simplemente lee todo IFS=' '
: ejecuciones de SPC (y SPC solamente) Un último 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á acostumbrado a $'ANSI-ESCAPED-STRING'
, es un ahorro de tiempo.
Si no incluye -r
(como en read -a arr <<<"$var"
), a continuación, lee se escapa la barra invertida. Esto se deja como ejercicio para el lector.
Para la segunda pregunta:
Para probar algo en una cadena, por lo general me apego a la case
, ya que esto puede verificar múltiples casos a la vez (nota: el caso solo ejecuta la primera coincidencia, si necesita usar multiploce las declaraciones de case
), y esta necesidad es muy a menudo el caso (juego de palabras intencionado):
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
Entonces puede establecer el valor de retorno para verificar SPC como este:
case "$var" in (*' '*) true;; (*) false;; esac
¿Por qué case
? Porque 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.
$ echo "This is a sentence." | tr -s " " "\012" This is a sentence.
Para buscar espacios, use grep:
$ echo "This is a sentence." | grep " " > /dev/null $ echo $? 0 $ echo "Thisisasentence." | grep " " > /dev/null $ echo $? 1
(A) Para dividir una oración en sus palabras (espacio separado) puede simplemente usar el IFS predeterminado usando
array=( $string )
Ejemplo que ejecuta el siguiente fragmento
#!/bin/bash sentence="this is the \"sentence\" 'you' want to split" words=( $sentence ) len="${#words[@]}" echo "words counted: $len" printf "%s\n" "${words[@]}" ## print array
saldrá
words counted: 8 this is the "sentence" 'you' want to split
Como puede ver, también puede usar comillas simples o dobles sin ningún problema
Notas:
– Esto es básicamente lo mismo que la respuesta de la mafia , pero de esta manera almacenas la matriz para cualquier necesidad adicional. Si solo necesita un bucle único, puede usar su respuesta, que es una línea más corta 🙂
– Consulte esta pregunta para obtener métodos alternativos para dividir una cadena en función del delimitador.
(B) Para buscar un personaje en una cadena, también puede usar una coincidencia de expresión regular.
Ejemplo para verificar la presencia de un carácter de espacio que puede usar:
regex='\s{1,}' if [[ "$sentence" =~ $regex ]] then echo "Space here!"; fi
Para verificar espacios solo con bash:
[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"