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.
bashsustitución de patrón ("${i//.}") comprueba si hay un.en un elemento. (Unacasedeclaración podría ser más simple, aunque menos similar al código del OP ).reading$arraypor 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$icontiene.(y también portátil parash). Si te gustan los kshismos, mira también:[[ $i = *.* ]]caseen las notas al final, pero estamos de acuerdo. (Desde el OP utiliza tanto<<<y matrices , esto no es mucho de unashpregunta.)En versiones anteriores de
bashusted 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
readocommand, esa división incluso tomaría el IFS para esa construcción (4.3 solucionó eso):Ese arreglado en 4.3:
Pero
$atodaví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
zshdó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$varen un elemento vacío.O use un shell con un operador de división adecuado:
zsh:rc:fishfuente
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
$INinvoca al operador split + glob. Aquí, no quieres la parte glob (pruebaIN=*-*-/*-17.0.0por ejemplo), así que querrás hacerloset -o noglobantes de invocarla. Vea mi respuesta para más detalles.IFSy configurarlo globalmente. Realmente solo desea cambiar el valor deIFSfor cuando$INse expande, y tampoco desea que se realice la expansión del nombre de ruta en la expansión. Además,OIFS=$IFSno distingue entre los casos en queIFSse estableció en una cadena vacía y cuandoIFSse desarmó por completo.