Como portar matrizes de estilo bash para ash?

12

Algum tempo atrás, escrevi um script bash que agora deve ser capaz de rodar em ambiente ash.

No bashera como:

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

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

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

Na realidade, existem cerca de 40 serviços em matriz, e quero fazer essa transição o mais simples e limpa possível. Sempre usaram bashismos. Agora estou em uma pitada com a tarefa de tornar os scripts mais portáteis.

Por motivos de portabilidade, provavelmente seria bom ter uma ashsolução pura . Mas, como tenho uma disposição bastante robusta busybox, posso sacrificar alguma portabilidade. Somente se a legibilidade melhorar muito, já que o script "limpo" também é uma métrica.

O que seria uma solução portátil e limpa nesse caso?

metamorfose
fonte

Respostas:

8

Antes de matrizes foram em bash, kshe outros reservatórios, o método usual era escolher um delimitador que não estava em qualquer um dos elementos (ou um que foi incomum para minimizar qualquer escapar necessário), e iterar uma cadeia que contém todos os elementos, separados por esse delimitador. Espaço em branco geralmente é a opção mais conveniente de delimitador, porque o shell já divide "palavras" por espaço em branco por padrão (você pode definir o IFS se desejar dividir em algo diferente).

Por exemplo:

# 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

$servicesNÃO deve ser citado aqui porque queremos que o shell o divida em "palavras".

cas
fonte
3

o ash não possui matrizes. A única coisa que se aproxima é os parâmetros posicionais, então você pode fazer

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

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

Se você precisar consultar a lista de serviços apenas uma vez, poderá usar um documento aqui:

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

Observe que os nomes dos serviços não devem ser citados na lista (embora "$service"provavelmente devam ser citados, a menos que você tenha um bom motivo para não fazê-lo). Se você deseja que os nomes dos serviços sejam recuados, use em <<-vez de <<e indente os nomes com guias:

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