Как перенести массив в bash-стиле в пепел?

13

Некоторое время назад я написал скрипт bash, который теперь должен работать в среде с ash.

На bashэто было похоже:

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

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

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

На самом деле в массиве около 40 сервисов, и я хочу сделать этот переход максимально безболезненным и чистым. Всегда использовал bashisms. Теперь я в затруднении с задачей сделать скрипты более переносимыми.

По причинам переносимости, вероятно, было бы неплохо иметь чистое ashрешение. Но так как busyboxв моем распоряжении есть достаточно надежный инструмент, я могу пожертвовать некоторой переносимостью. Только если читаемость значительно улучшится, так как «чистый» скрипт тоже показатель.

Каким было бы портативное и чистое решение в этом случае?

metamorphling
источник

Ответы:

8

Перед тем как массивы были bash, kshи другие оболочки, обычный метод был выбрать разделитель , который не был ни в одном из элементов (или тот , который был редкостью , чтобы свести к минимуму любых требуемых побега), и итерация над строкой , содержащей все элементы, разделены этим разделителем. Пробел, как правило, является наиболее удобным выбором разделителя, потому что оболочка уже разбивает «слова» по пробелам по умолчанию (вы можете установить IFS, если хотите, чтобы он разделялся на что-то другое).

Например:

# 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здесь НЕ должно быть двойных кавычек, потому что мы хотим, чтобы оболочка разделяла его на «слова».

саз
источник
3

У пепла нет массивов. Единственное, что близко, это позиционные параметры, так что вы можете сделать

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

for service in "$@"
do
   START $service
done
Гленн Джекман
источник
3

Если вам нужно обратиться к списку услуг только один раз, вы можете использовать здесь документ:

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

Обратите внимание, что имена служб не должны указываться в списке (хотя, "$service"вероятно, следует указывать их, если у вас нет веских причин не делать этого). Если вы хотите, чтобы имена сервисов были сделаны с отступом, используйте <<-вместо них <<имена с вкладками:

while IFS= read -r service
do
   START "$service"
done <<- END
        service1.service
        service2.service
        service3.service
END
Скотт
источник