web-dev-qa-db-fra.com

Comment porter des matrices de style Bash à Ash?

Il y a quelque temps, j'ai écrit un script Bash qui devrait maintenant pouvoir courir dans l'environnement avec ash.

Dans bash c'était comme:

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

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

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

En réalité, il y a 40 services de tableau et je tiens à rendre cette transition aussi sans douleur et propre que possible. Ont toujours utilisé bashisms. Maintenant, je suis dans une pincée avec la tâche pour rendre les scripts plus portables.

Pour des raisons de portabilité, il serait probablement agréable d'avoir une solution pure ash. Mais depuis que j'ai une assez robuste busybox à ma disposition, je pourrais sacrifier une certaine portabilité. Seulement si la lisibilité améliore beaucoup, puisque le script "propre" est une métrique aussi.

Quel serait portable et propre solution dans ce cas?

12
metamorphling

Avant que les tableaux n'étaient en bash, ksh, et d'autres coquilles, la méthode habituelle consistait à choisir un délimiteur qui n'était dans aucun des éléments (ou un peu rare de minimiser les échappés nécessaires ), et itérer sur une chaîne contenant tous les éléments, séparés par ce délimiteur. WhitSpace est généralement le choix du délimiteur le plus pratique, car la coquille divise déjà des "mots" par blancheur par défaut (vous pouvez définir des ifs si vous voulez qu'il soit divisé sur quelque chose de différent).

Par exemple:

# 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

$services devrait [~ # ~] pas [~ # ~ ~] Soyez double-cité ici parce que nous voulez la coquille de la diviser en "mots".

8
cas

Si vous devez vous reporter à la liste des services une seule fois, vous pouvez utiliser un document ici:

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

Notez que les noms de service ne doivent pas être cités dans la liste (bien que "$service" devrait probablement être cité, à moins que vous n'ayez une bonne raison de ne pas). Si vous souhaitez avoir les noms de service en retrait, utilisez <<- à la place de << et indenter les noms avec des onglets:

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