Искусство программирования на языке сценариев командной оболочки
Шрифт:
until [ "$i" -gt "$UPPER_LIMIT" ]
do
if [ "${Primes[i]}" -eq "$PRIME" ]
# Не следует проверять вторично числа, которые уже признаны составными.
then
t=$i
while [ "$t" -le "$UPPER_LIMIT" ]
do
let "t += $i "
Primes[t]=$NON_PRIME
# Все числа, которые делятся на $t без остатка, пометить как составные.
done
fi
let "i += 1"
done
}
#
initialize
sift
print_primes
# Это называется структурным программированием.
echo
exit 0
# ----------------------------------------------- #
# Код, приведенный ниже, не исполняется из-за команды exit, стоящей выше.
# Улучшенная версия, предложенная Stephane Chazelas,
# работает несколько быстрее.
# Должен вызываться с аргументом командной строки, определяющем верхний предел.
UPPER_LIMIT=$1 # Из командной строки.
let SPLIT=UPPER_LIMIT/2 # Рассматривать делители только до середины диапазона.
Primes=( '' $(seq $UPPER_LIMIT) )
i=1
until (( ( i += 1 ) > SPLIT )) # Числа из верхней половины диапазона могут не рассматриваться.
do
if [[ -n $Primes[i] ]]
then
t=$i
until (( ( t += i ) > UPPER_LIMIT ))
do
Primes[t]=
done
fi
done
echo ${Primes[*]}
exit 0
Сравните этот сценарий с генератором простых чисел, не использующим массивов, Пример A-18.
– -
Массивы позволяют эмулировать некоторые структуры данных, поддержка которых в Bash не предусмотрена.
Пример 25-9. Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")
#!/bin/bash
# stack.sh: Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")
# Подобно стеку процессора, этот "стек" сохраняет и возвращает данные по принципу
#+ "первый вошел -- последний вышел".
BP=100 # Базовый указатель на массив-стек.
# Дно стека -- 100-й элемент.
SP=$BP # Указатель вершины стека.
# Изначально -- стек пуст.
Data= # Содержимое вершины стека.
# Следует использовать дополнительную переменную,
#+ из-за ограничений на диапазон возвращаемых функциями значений.
declare -a stack
push # Поместить элемент на вершину стека.
{
if [ -z "$1" ] #
then
return
fi
let "SP -= 1" # Переместить указатель стека.
stack[$SP]=$1
return
}
pop # Снять элемент с вершины стека.
{
Data= # Очистить переменную.
if [ "$SP" -eq "$BP" ] # Стек пуст?
then
return
fi # Это предохраняет от выхода SP за границу стека -- 100,
Data=${stack[$SP]}
let "SP += 1" # Переместить указатель стека.
return
}
status_report # Вывод вспомогательной информации.
{
echo "-------------------------------------"
echo "ОТЧЕТ"
echo "Указатель стека SP = $SP"
echo "Со стека был снят элемент \""$Data"\""
echo "-------------------------------------"
echo
}
# =======================================================
# А теперь позабавимся.
echo
# Попробуем вытолкнуть что-нибудь из пустого стека.
pop
status_report
echo
push garbage
pop
status_report # Втолкнуть garbage, вытолкнуть garbage.
value1=23; push $value1
value2=skidoo; push $value2
value3=FINAL; push $value3
pop # FINAL
status_report
pop # skidoo
status_report
pop # 23
status_report # Первый вошел -- последний вышел!
# Обратите внимание как изменяется указатель стека на каждом вызове функций push и pop.
echo
# =======================================================
# Упражнения:
# -----------
# 1) Измените функцию "push" таким образом,
# + чтобы она позволяла помещать на стек несколько значений за один вызов.
# 2) Измените функцию "pop" таким образом,
# + чтобы она позволяла снимать со стека несколько значений за один вызов.
# 3) Попробуйте написать простейший калькулятор, выполняющий 4 арифметических действия?
# + используя этот пример.
exit 0
– -
Иногда, манипуляции с "индексами" массивов могут потребовать введения переменных для хранения промежуточных результатов. В таких случаях вам предоставляется лишний повод подумать о реализации проекта на более мощном языке программирования, например Perl или C.