Мендель Купер - Искусство программирования на языке сценариев командной оболочки
# Вероятно из-за ошибок округления и несовершенства генератора случайных чисел.
echo
# }
exit 0
# Самое время задуматься над тем, является ли сценарий удобным средством
#+ для выполнения большого количества столь сложных вычислений.
#
# Тем не менее, этот пример может расцениваться как
# 1) Доказательство возможностей языка командной оболочки.
# 2) Прототип для "обкатки" алгоритма перед тем как перенести
#+ его на высокоуровневые языки программирования компилирующего типа.
dc
Утилита dc (desk calculator) -- это калькулятор, использующий "Обратную Польскую Нотацию", и ориентированный на работу со стеком.
Многие стараются избегать испоьзования dc, из-за непривычной формы записи операндов и операций. Однако, dc имеет и своих сторонников.
Пример 12-36. Преобразование чисел из десятичной в шестнадцатиричную систему счисления
#!/bin/bash
# hexconvert.sh: Преобразование чисел из десятичной в шестнадцатиричную систему счисления.
BASE=16 # Шестнадцатиричная.
if [ -z "$1" ]
then
echo "Порядок использования: $0 number"
exit $E_NOARGS
# Необходим аргумент командной строки.
fi
# Упражнение: добавьте проверку корректности аргумента.
hexcvt ()
{
if [ -z "$1" ]
then
echo 0
return # "Return" 0, если функции не был передан аргумент.
fi
echo ""$1" "$BASE" o p" | dc
# "o" устанавливает основание системы счисления для вывода.
# "p" выводит число, находящееся на вершине стека.
# См. 'man dc'.
return
}
hexcvt "$1"
exit 0
Изучение страниц info dc позволит детальнее разобраться с утилитой. Однако, отряд "гуру", которые могут похвастать своим знанием этой мощной, но весьма запутанной утилиты, весьма немногочислен.
Пример 12-37. Разложение числа на простые множители
#!/bin/bash
# factr.sh: Разложение числа на простые множители
MIN=2 # Не работает с числами меньше 2.
E_NOARGS=65
E_TOOSMALL=66
if [ -z $1 ]
then
echo "Порядок использования: $0 number"
exit $E_NOARGS
fi
if [ "$1" -lt "$MIN" ]
then
echo "Исходное число должно быть больше или равно $MIN."
exit $E_TOOSMALL
fi
# Упражнение: Добавьте проверку типа числа (не целые числа должны отвергаться).
echo "Простые множители для числа $1:"
# ---------------------------------------------------------------------------------
echo "$1[p]s2[lip/dli%0=1dvsr]s12sid2%0=13sidvsr[dli%0=1lrli2+dsi!>.]ds.xd1<2" | dc
# ---------------------------------------------------------------------------------
# Автор вышеприведенной строки: Michel Charpentier < [email protected]>.
# Используется с его разрешения (спасибо).
exit 0
awk
Еще один способ выполнения математических операций, над числами с плавающей запятой, состоит в создании сценария-обертки, использующего математические функции awk.
Пример 12-38. Расчет гипотенузы прямоугольного треугольника
#!/bin/bash
# hypotenuse.sh: Возвращает "гипотенузу" прямоугольного треугольника.
# ( корень квадратный от суммы квадратов катетов)
ARGS=2 # В сценарий необходимо передать два катета.
E_BADARGS=65 # Ошибка в аргументах.
if [ $# -ne "$ARGS" ] # Проверка количества аргументов.
then
echo "Порядок использования: `basename $0` катет_1 катет_2"
exit $E_BADARGS
fi
AWKSCRIPT=' { printf( "%3.7fn", sqrt($1*$1 + $2*$2) ) } '
# команды и параметры, передаваемые в awk
echo -n "Гипотенуза прямоугольного треугольника, с катетами $1 и $2, = "
echo $1 $2 | awk "$AWKSCRIPT"
exit 0
12.9. Прочие команды
Команды, которые нельзя отнести ни к одной из вышеперечисленных категорий
jot, seq
Эти утилиты выводят последовательность целых чисел с шагом, заданным пользователем.
По-умолчанию, выводимые числа отделяются друг от друга символом перевода строки, однако, с помощью ключа -s может быть задан другой разделитель.
bash$ seq 5
1
2
3
4
5
bash$ seq -s : 5
1:2:3:4:5
Обе утилиты, и jot, и seq, очень удобно использовать для генерации списка аргументов в цикле for.
Пример 12-39. Использование seq для генерации списка аргументов цикла for
#!/bin/bash
# Утилита "seq"
echo
for a in `seq 80` # или так: for a in $( seq 80 )
# То же самое, что и for a in 1 2 3 4 5 ... 80 (но как экономит время и силы!).
# Можно использовать и 'jot' (если эта утилита имеется в системе).
do
echo -n "$a "
done # 1 2 3 4 5 ... 80
# Пример использования вывода команды для генерации
# [списка] аргументов цикла "for".
echo; echo
COUNT=80 # Да, 'seq' допускает указание переменных в качестве параметра.
for a in `seq $COUNT` # или так: for a in $( seq $COUNT )
do
echo -n "$a "
done # 1 2 3 4 5 ... 80
echo; echo
BEGIN=75
END=80
for a in `seq $BEGIN $END`
# Если "seq" передаются два аргумента, то первый означает начальное число последовательности,
#+ второй -- последнее,
do
echo -n "$a "
done # 75 76 77 78 79 80
echo; echo
BEGIN=45
INTERVAL=5
END=80
for a in `seq $BEGIN $INTERVAL $END`
# Если "seq" передется три аргумента, то первый аргумент -- начальное число в последовательности,
#+ второй -- шаг последовательности,
#+ и третий -- последнее число в последовательности.
do
echo -n "$a "
done # 45 50 55 60 65 70 75 80
echo; echo
exit 0
getopt
Команда getopt служит для разбора командной строки, выделяя из нее ключи -- символы, с предшествующим знаком дефис. Этой утилите имеется, встроенный в Bash, аналог -- getopts, более мощная и универсальная команда.
Пример 12-40. Использование getopt для разбора аргументов командной строки
#!/bin/bash
# ex33a.sh
# Попробуйте следующие варианты вызова этого сценария.
# sh ex33a -a
# sh ex33a -abc
# sh ex33a -a -b -c
# sh ex33a -d
# sh ex33a -dXYZ
# sh ex33a -d XYZ
# sh ex33a -abcd
# sh ex33a -abcdZ
# sh ex33a -z
# sh ex33a a
# Объясните полученные результаты.
E_OPTERR=65
if [ "$#" -eq 0 ]
then # Необходим по меньшей мере один аргумент.
echo "Порядок использования: $0 -[options a,b,c]"
exit $E_OPTERR
fi
set -- `getopt "abcd:" " [email protected]"`
# Запись аргументов командной строки в позиционные параметры.
# Что произойдет, если вместо " [email protected]" указать "$*"?
while [ ! -z "$1" ]
do
case "$1" in
-a) echo "Опция "a"";;
-b) echo "Опция "b"";;
-c) echo "Опция "c"";;
-d) echo "Опция "d" $2";;
*) break;;
esac
shift
done
# Вместо 'getopt' лучше использовать встроенную команду 'getopts',
# См. "ex33.sh".
exit 0
run-parts
Команда run-parts[ 33 ] запускает на исполнение все сценарии, в порядке возрастания имен файлов-сценариев, в заданном каталоге. Естественно, файлы сценариев должны иметь права на исполнение.
Демон crond вызывает run-parts для запуска сценариев из каталогов /etc/cron.*.
yes
По-умолчанию, команда yes выводит на stdout непрерывную последовательность символов y, разделенных символами перевода строки. Исполнение команды можно прервать комбинацией клавиш control-c. Команду yes можно заставить выводить иную последовательность символов. Теперь самое время задаться вопросом о практической пользе этой команды. Основное применение этой команды состоит в том, что вывод от нее может быть передан, через конвейер, другой команде, ожидающей реакции пользователя. В результате получается, своего рода, слабенькая версия команды expect.