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 argumento. Por ej ${2} == "cat cat file"
. ¿Cómo puedo recorrerlo?
Además, ¿cómo puedo verificar si una cadena contiene espacios?
Respuestas:
¿Intentó simplemente pasar la variable de cadena a un
for
bucle? Bash, por ejemplo, se dividirá en espacios en blanco automáticamente.fuente
A=${A}${word})
.touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; done
salidas en[NOPE] [a] [NOPE]
lugar de lo esperado[*] [a] [*]
(LFs reemplazados por SPC para facilitar la lectura).Me gusta la conversión a una matriz, para poder acceder a elementos individuales:
ahora puede acceder a elementos individuales directamente (comienza con 0):
o convertir de nuevo a cadena para hacer un bucle:
Por supuesto, el bucle a través de la cadena directamente se respondió antes, pero esa respuesta tenía la desventaja de no realizar un seguimiento de los elementos individuales para su uso posterior:
Consulte también Referencia de matriz de bash .
fuente
touch NOPE; var='* a *'; arr=($var); set | grep ^arr=
salidas enarr=([0]="NOPE" [1]="a" [2]="NOPE")
lugar de lo esperadoarr=([0]="*" [1]="a" [2]="*")
Solo use los shells "set" incorporados. Por ejemplo,
Después de eso, las palabras individuales en $ texto estarán en $ 1, $ 2, $ 3, etc. Para mayor solidez, generalmente se hace
para manejar el caso donde $ text está vacío o comienza con un guión. Por ejemplo:
Esto imprime
fuente
awk
peroset
es mucho más fácil. Ahora soyset
fanboy. Gracias @Idelic!touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; done
salidas en[NOPE] [a] [NOPE]
lugar de las esperadas[*] [a] [*]
. ¡Úselo solo si está 101% seguro de que no hay metacaracteres SHELL en la cadena dividida!set -f
antesset -- $var
yset +f
después deshabilitar el globbing.set -f
su solución también es seguro. Peroset +f
es el valor predeterminado de cada shell, por lo que es un detalle esencial, que debe tenerse en cuenta, porque probablemente otros no lo sepan (como yo también).La forma probablemente más fácil y segura en BASH 3 y superior es:
(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:(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:
Salidas de lo esperado
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:
Produce algo como:
Como puede ver, los espacios también se pueden preservar de esta manera:
salidas
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 terminaIFS=''
: Sin separación de campo, solo lee todoIFS=' '
: Ejecuciones de SPC (y solo SPC)Algun ultimo ejemplo
salidas
mientras
salidas
Por cierto:
Si no estás acostumbrado
$'ANSI-ESCAPED-STRING'
, es un ahorro de tiempo.Si no incluye
-r
(como enread -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, usecase
declaraciones multiplce ), y esta necesidad suele ser el caso (juego de palabras destinado a):Por lo tanto, puede establecer el valor de retorno para verificar SPC de esta manera:
¿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.fuente
set -f
oset -o noglob
cambiar de globbing, de modo que los metacaracteres de shell ya no causen daño en este contexto. Pero realmente no soy amigo de eso, ya que esto deja mucho poder del shell / es muy propenso a errores para cambiar esta configuración.;&
lograr eso. No estoy seguro de en qué versión de bash apareció. Soy un usuario 4.3;&
es la caída forzada sin verificación de patrones como en C. Y también existe la;;&
que continúa haciendo las verificaciones de patrones adicionales. Así;;
es comoif ..; then ..; else if ..
y;;&
es comoif ..; then ..; fi; if ..
, donde;&
es comom=false; if ..; then ..; m=:; fi; if $m || ..; then ..
: uno nunca deja de aprender (de otros););;&
antes de que comentaras: D Gracias, y que la concha esté contigo;)Para verificar espacios, use grep:
fuente
echo "X" |
por lo general se puede sustituir por<<<"X"
, como esto:grep -s " " <<<"This contains SPC"
. Puedes ver la diferencia si haces algo comoecho X | read var
en contraste conread var <<< X
. Solo la última importa la variablevar
al shell actual, mientras que para acceder a ella en la primera variante debe agrupar así:echo X | { read var; handle "$var"; }
(A) Para dividir una oración en sus palabras (separadas por espacios), simplemente puede usar el IFS predeterminado usando
Ejemplo ejecutando el siguiente fragmento
saldrá
Como puede ver, también puede usar comillas simples o dobles sin ningún problema.
Notas:
esto es básicamente lo mismo de respuesta mafia , pero de esta manera almacena la matriz para cualquier otra necesidad. Si solo necesita un solo bucle, 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 carácter 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:
fuente
Para comprobar espacios solo con bash:
fuente
Esto genera cada palabra, puede procesar esa lista como mejor le parezca después.
fuente