sustituir - ¿Cómo dividir una cadena en múltiples cadenas separadas por al menos un espacio en bash shell?
sed linux (7)
¿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.
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?
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 enread -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.
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
Para verificar espacios solo con bash:
[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"
Simplemente use el "set" de proyectiles incorporado. Por ejemplo,
set $text
Después de eso, las palabras individuales en $ text estarán en $ 1, $ 2, $ 3, etc. Para la solidez, uno usualmente lo hace
set -- junk $text shift
para manejar el caso donde $ text está vacío o comienza con un guión. Por ejemplo:
text="This is a test" set -- junk $text shift for word; do echo "[$word]" done
Esto imprime
[This] [is] [a] [test]
(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 mob , 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
$ 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