Como portar matrizes estilo bash para cinzas?

5

Algum tempo atrás eu escrevi um script bash que agora deve ser executado em ambiente com ash .

Em bash , foi 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 40 serviços em array e quero tornar essa transição o mais simples e limpa possível. Sempre usei bash isms. Agora estou em apuros com a tarefa de tornar os scripts mais portáteis.

Por razões de portabilidade, provavelmente seria bom ter uma solução ash pura. Mas desde que eu tenho um busybox bastante robusto à minha disposição eu poderia sacrificar alguma portabilidade. Somente se a legibilidade melhorar muito, pois o script "limpo" também é uma métrica.

Qual seria a solução portável e clean nesse caso?

    
por metamorphling 08.08.2017 / 04:14

3 respostas

6

Antes dos arrays estarem em bash , ksh e outros shells, o método usual era escolher um delimitador que não estivesse em nenhum dos elementos (ou um que fosse incomum para minimizar qualquer escape necessário), e iterar sobre uma string contendo todos os elementos, separados por esse delimitador. O espaço em branco é geralmente a opção de delimitador mais conveniente porque o shell já divide "palavras" por espaço em branco por padrão (você pode definir o IFS se quiser 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

$services deve NÃO ser citado duas vezes aqui porque queremos o shell para dividi-lo em "palavras".

    
por 08.08.2017 / 04:31
2

Se você precisar consultar a lista de serviços apenas uma vez, você pode usar um aqui-doc:

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

Observe que os nomes de serviço não devem ser citados na lista (embora "$service" provavelmente deva ser citado, a menos que você tenha uma boa razão para não fazer isso). Se você gostaria de ter os nomes de serviço recuados, use <<- em vez de << e indente os nomes com abas:

while IFS= read -r service
do
   START "$service"
done <<- END
        service1.service
        service2.service
        service3.service
END
    
por 08.08.2017 / 08:03
1

ash não possui matrizes. A única coisa que chega perto são os parâmetros posicionais, então você poderia fazer

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

for service in "$@"
do
   START $service
done
    
por 08.08.2017 / 04:30