He escrito una secuencia de comandos de muestra para dividir la cadena pero no funciona como se esperaba
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
salida
One
XX
X
17.0.0
17 0 0
pero esperaba que la salida fuera:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
usuario112232
fuente
fuente
Respuestas:
Solución, (ver también la respuesta de S. Chazelas para el fondo), con salida sensata:
Salida:
Notas:
Es mejor poner el segundo bucle condicional en el primer bucle.
bash
sustitución de patrón ("${i//.}"
) comprueba si hay un.
en un elemento. (Unacase
declaración podría ser más simple, aunque menos similar al código del OP ).read
ing$array
por entrada<<< "${ADDR[3]}"
es menos general que<<< "$i"
. Evita la necesidad de saber qué elemento tiene el.
s.El código supone que la impresión " Elemento: 17.0.0 " no es intencional. Si se pretende ese comportamiento , reemplace el bucle principal con:
fuente
case $i in (*.*) ...
sería una forma más canónica de verificar que$i
contiene.
(y también portátil parash
). Si te gustan los kshismos, mira también:[[ $i = *.* ]]
case
en las notas al final, pero estamos de acuerdo. (Desde el OP utiliza tanto<<<
y matrices , esto no es mucho de unash
pregunta.)En versiones anteriores de
bash
usted tenía que citar variables después<<<
. Eso fue arreglado en 4.4. En versiones anteriores, la variable se dividiría en IFS y las palabras resultantes se unirían en el espacio antes de almacenarse en el archivo temporal que constituye esa<<<
redirección.En 4.2 y anteriores, al redirigir las construcciones como
read
ocommand
, esa división incluso tomaría el IFS para esa construcción (4.3 solucionó eso):Ese arreglado en 4.3:
Pero
$a
todavía está sujeto a la división de palabras allí:En 4.4:
Para la portabilidad a versiones anteriores, indique su variable (o use de
zsh
dónde<<<
proviene en primer lugar y eso no tiene ese problema)Tenga en cuenta que ese enfoque para dividir una cadena solo funciona para cadenas que no contienen caracteres de nueva línea. También tenga en cuenta que
a..b.c.
se dividiría en"a"
,""
,"b"
,"c"
(sin vaciar último elemento).Para dividir cadenas arbitrarias, puede usar el operador split + glob en su lugar (lo que lo haría estándar y evitaría almacenar el contenido de una variable en un archivo temporal como lo
<<<
hace):o:
El
''
es preservar un elemento vacío final si lo hay. Eso también dividiría un elemento vacío$var
en un elemento vacío.O use un shell con un operador de división adecuado:
zsh
:rc
:fish
fuente
Con awk te costaría una línea:
-F'[-.]'
- separador de campo basado en múltiples caracteres, en nuestro caso-
y.
La salida:
fuente
IFS=-. read -r a array <<< "$IN"
Aquí mi camino:
resultado como se esperaba:
fuente
$IN
invoca al operador split + glob. Aquí, no quieres la parte glob (pruebaIN=*-*-/*-17.0.0
por ejemplo), así que querrás hacerloset -o noglob
antes de invocarla. Vea mi respuesta para más detalles.IFS
y configurarlo globalmente. Realmente solo desea cambiar el valor deIFS
for cuando$IN
se expande, y tampoco desea que se realice la expansión del nombre de ruta en la expansión. Además,OIFS=$IFS
no distingue entre los casos en queIFS
se estableció en una cadena vacía y cuandoIFS
se desarmó por completo.