Во-первых, агрессивно современное решение:
#!/bin/bash
# ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh
np=$(nproc --all)
cores=()
for ((i=0; i<np; i++)); do
printf -v suffix '%02i' "$i"
cores[$i]=$suffix
done
Это генерирует один индексный массив: Его ключи являются основными числами, и его значения суффикс строки. Таким образом, вы можете перебрать более "${!cores[@]}"
, чтобы получить список номеров ядер; над "${cores[@]}"
, чтобы получить список строк суффикса, или используйте "${cores[$i]}"
для поиска суффикса для ядра $i
.
Затем раствор ближе к исходному коду, построенное для современного Баша:
#!/bin/bash
# ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh
np=$(nproc --all)
cores=""; suffixes=""
for ((i=0; i<np; i++)); do
printf -v suffix '%02i' "$i"
cores+=" $i"
suffixes+=" $suffix"
done
Вы можете также построить только основные номера внутри массива и вычислить число суффиксов в одном шаге:
# read cores from string into an array to allow safe evaluation even with unknown IFS
IFS=' ' read -r -a cores_arr <<<"$cores"
# ...and expand the full array, repeating the format string for every element
printf -v suffixes '%02i ' "${cores_arr[@]}"
Примечательно:
Итерация по расширенному массиву, т.е. for i in $cores
, как правило, плохая практика - если ваши ценности гарантируется только быть числовыми это может быть безопасным, но быть в курсе побочных эффектов:
- Глоб выражения внутри строки расширяются: Если вы каким-то образом имел
*
в ваших данных, вы можете перебирать файлы в текущем каталоге.
- String-splitting не допускает мелкозернистого управления границами элементов, которые делают массивы. У вас может быть
array=("item one" "item two")
для хранения двух предметов с пробелами в обоих именах; если вы пробовали настройки string=' "item one" "item two" '
, вы получите "item
как одно слово, one"
в качестве второго слова и т.д.
Следовательно, итерация по элементам массива - даже если это означает, что чтение из строки в Массив - настоятельно рекомендуется.
Зацикливание на произвольное количество предметов лучше всего сделать с помощью C-style for
loop.
- В приведенных выше примерах нет внешних команд, кроме
nproc
. Это означает, что мы не зависим от инструментов, отличных от POSIX, таких как seq
.
- Использование
printf -v suffix
записывает результат операций форматирования строк, выполняемых printf
непосредственно в переменную с именем suffix
. (Кроме того: ksh93 не имеет printf -v
, но распознает использование printf внутри $()
и избегает штрафа подзаголовка). См. the bash-hackers page on printf
.
- Следовательно: нет никаких подоболочек, кроме тех, которые необходимы для запуска указанной внешней команды и записи ее вывода. (Каждой подоболочке требуется
fork()
с другой копией оболочки после использования mkfifo()
, чтобы сгенерировать FIFO для захвата его вывода, считывая этот вывод: wait()
для выхода из подоболочки и т. Д., Поэтому они лучше всего сохраняются за пределами жестких циклов).
Если вам нужна совместимость с POSIX ш, напротив, мы до сих пор $(())
но не (())
(и не +=
работы, за исключением в контексте математики, и нет C-стиль for
петли на всех). Это оставляет нас с:
#!/bin/sh
build_suffix() {
np=$1; i=0
while [ "$i" -lt "$np" ]; do
printf '%02i ' "$i"
i=$((i+1))
done
}
suffixes=$(build_suffix "$(nproc --all)")
... который не дает нам ответ с точно два подоболочек, независимо от того, сколько раз мы петлевые, поставив весь цикл внутри одной подоболочки.
'for ((i = 0; i
' suffixes = "$ (printf '% 02i' $ (seq $ (nproc -all)))" ' – twalberg
@twalberg, ... если бы мы были готовы потребовать использование не-POSIX-инструмента который не поставляется с bash, например 'seq'. Eww. –