¿Cómo portar matrices de estilo bash a cenizas?

12

Hace algún tiempo escribí un script bash que ahora debería poder ejecutarse en un entorno ash.

En bashfue como:

services=( "service1.service"
           "service2.service"                                       
           "service3.service" )  

for service in "${services[@]}"
do
   START $service                   
done

START()
{
   echo "Starting "$1
   systemctl start $1
}

En realidad, hay como 40 servicios en matriz, y quiero que esta transición sea lo más sencilla y limpia posible. Siempre he estado usando bashismos. Ahora estoy en apuros con la tarea de hacer que los scripts sean más portátiles.

Por razones de portabilidad, probablemente sería bueno tener una ashsolución pura . Pero como tengo un dispositivo bastante robusto busyboxa mi disposición, podría sacrificar algo de portabilidad. Solo si la legibilidad mejora mucho, ya que el script "limpio" también es una métrica.

¿Cuál sería la solución portátil y limpia en este caso?

metamorphling
fuente

Respuestas:

8

Antes de matrices estaban en bash, kshy otros proyectiles, el método habitual era que elegir un delimitador que no estaba en ninguno de los elementos (o uno que era raro para reducir al mínimo cualquier escape es necesario), y iterar sobre una cadena que contiene todos los elementos, separados por ese delimitador. El espacio en blanco suele ser la opción de delimitador más conveniente porque el shell ya divide las "palabras" por espacios en blanco de forma predeterminada (puede configurar IFS si desea que se divida en algo diferente).

Por ejemplo:

# backslash-escape any non-delimiter whitespace and all other characters that
# have special meaning to the shell, e.g. globs, parenthesis, ampersands, etc.
services='service1.service service2.service service3.service'

for s in $services ; do  # NOTE: do not double-quote $services here.
  START "$s"
done

$servicesNO debería ser doblemente citado aquí porque queremos que el shell lo divida en "palabras".

cas
fuente
3

ash no tiene matrices. Lo único que se acerca son los parámetros posicionales, por lo que podría hacer

set -- "service1.service" \
       "service2.service" \
       "service3.service"

for service in "$@"
do
   START $service
done
Glenn Jackman
fuente
3

Si necesita consultar la lista de servicios solo una vez, puede usar un documento aquí:

while IFS= read -r service
do
   START "$service"
done << END
service1.service
service2.service
service3.service
END

Tenga en cuenta que los nombres de los servicios no deben citarse en la lista (aunque "$service"probablemente deberían citarse, a menos que tenga una buena razón para no hacerlo). Si desea sangrar los nombres de los servicios, use en <<-lugar de <<y sangra los nombres con pestañas:

while IFS= read -r service
do
   START "$service"
done <<- END
        service1.service
        service2.service
        service3.service
END
Scott
fuente