Come eseguire il porting su array in stile bash su ash?


13

Qualche tempo fa ho scritto uno script bash che ora dovrebbe essere in grado di funzionare in ambiente ash.

In bashesso era come:

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

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

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

In realtà ci sono circa 40 servizi in array e voglio rendere questa transizione il più indolore e pulita possibile. Ho sempre usato gli bashismi. Ora sono in difficoltà con il compito di rendere gli script più portatili.

Per motivi di portabilità probabilmente sarebbe bello avere una ashsoluzione pura . Ma dal momento che ne ho una abbastanza robusta busybox, potrei sacrificare un po 'di portabilità. Solo se la leggibilità migliora molto, poiché anche lo script "clean" è una metrica.

Quale sarebbe la soluzione portatile e pulita in questo caso?

Risposte:


8

Prima che le matrici fossero presenti bash, kshe altre shell, il solito metodo era quello di scegliere un delimitatore che non si trovava in nessuno degli elementi (o uno insolito per ridurre al minimo l'eventuale escape necessario) e iterare su una stringa contenente tutti gli elementi, separati da quel delimitatore. Lo spazio bianco è di solito la scelta del delimitatore più conveniente perché la shell divide già "parole" per spazio bianco per impostazione predefinita (puoi impostare IFS se vuoi che si divida su qualcosa di diverso).

Per esempio:

# 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

$servicesNON dovremmo essere tra virgolette qui perché vogliamo che la shell lo divida in "parole".


3

la cenere non ha array. L'unica cosa che si avvicina sono i parametri posizionali, quindi potresti farlo

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

for service in "$@"
do
   START $service
done

3

Se devi fare riferimento all'elenco dei servizi una sola volta, puoi utilizzare un here-doc:

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

Si noti che i nomi dei servizi non devono essere citati nell'elenco (anche se "$service"probabilmente dovrebbero essere citati, a meno che non si abbia una buona ragione per non farlo). Se si desidera far rientrare i nomi dei servizi, utilizzare <<-invece <<e rientrare i nomi con le schede:

while IFS= read -r service
do
   START "$service"
done <<- END
        service1.service
        service2.service
        service3.service
END
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.