У цій відповіді я лише дам деякі загальні поради, а не орієнтири. Тести - єдиний спосіб надійно відповісти на запитання щодо продуктивності. Але оскільки ви не кажете, скільки даних ви маніпулюєте, і як часто ви виконуєте цю операцію, немає ніякого способу зробити корисний орієнтир. Що ефективніше для 10 предметів, а що ефективніше для 1000000 предметів, це часто не те саме.
Як правило, виклик зовнішніх команд коштує дорожче, ніж робити щось із чистими конструкціями оболонок, якщо чистий код оболонки не передбачає циклу. З іншого боку, цикл оболонки, який повторюється над великою або великою кількістю рядка, ймовірно, буде повільнішим, ніж одне виклик інструменту спеціального призначення. Наприклад, ваш цикл виклику cut
може бути помітно повільним на практиці, але якщо ви знайдете спосіб зробити всю справу за допомогою одного cut
виклику, що, швидше за все, буде швидше, ніж зробити те ж саме за допомогою маніпуляції з рядком в оболонці.
Зауважте, що точка відсікання може сильно відрізнятися між системами. Це може залежати від ядра, від того, як налаштовано планувальник ядра, файлової системи, що містить зовнішні виконувані файли, від того, який тиск процесора та пам'яті існує на даний момент, та багатьох інших факторів.
Не закликайте expr
виконувати арифметику, якщо ви взагалі стурбовані продуктивністю. Насправді взагалі не закликайте expr
виконувати арифметику. Оболонки мають вбудовану арифметику, яка зрозуміліша і швидша, ніж викликати expr
.
Здається, ви використовуєте bash, оскільки ви використовуєте bash конструкції, яких немає в sh. То чому б на землі ви не використовували масив? Масив - це найбільш природне рішення, і це, швидше за все, буде також найшвидшим. Зауважте, що індекси масиву починаються з 0.
list=(1 2 3 5 9 8 6 90 84 9 3 2 15 75 55)
for ((count = 0; count += 3; count < ${#list[@]})); do
echo "${list[$count]}"
done
Ваш сценарій може бути швидшим, якщо ви використовуєте sh, якщо ваша система має тире або ksh, sh
а не bash. Якщо ви використовуєте sh, ви не отримаєте назви масивів, але ви все одно отримаєте масив одного з позиційних параметрів, з яким ви можете встановити set
. Для доступу до елемента в позиції, яка не відома до часу виконання, вам потрібно скористатися eval
(подбайте про те, щоб цитувати речі правильно!).
# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
count=1
while [ $count -le $# ]; do
eval "value=\${$count}"
echo "$value"
count=$((count+1))
done
Якщо ви хочете лише один раз отримати доступ до масиву і збираєтесь зліва направо (пропускаючи деякі значення), ви можете використовувати shift
замість змінних індексів.
# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
while [ $# -ge 1 ]; do
echo "$1"
shift && shift && shift
done
Який підхід швидший, залежить від оболонки та кількості елементів.
Інша можливість - використовувати обробку рядків. Має перевагу не використовувати позиційні параметри, тому ви можете використовувати їх для чогось іншого. Це буде повільніше для великого обсягу даних, але це навряд чи помітно зміниться для невеликих обсягів даних.
# List elements must be separated by a single space (not arbitrary whitespace)
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
while [ -n "$list" ]; do
echo "${list% *}"
case "$list" in *\ *\ *\ *) :;; *) break;; esac
list="${list#* * * }"
done