Мендель Купер - Искусство программирования на языке сценариев командной оболочки
# agram.sh: Игры с анаграммами.
# Поиск анаграмм...
LETTERSET=etaoinshrdlu
anagram "$LETTERSET" | # Найти все анаграммы в наборе символов...
grep '.......' | # состоящие, как минимум из 7 символов,
grep '^is' | # начинающиеся с 'is'
grep -v 's$' | # исключая множественное число
grep -v 'ed$' # и глаголы в прошедшем времени
# Здесь используется утилита "anagram"
#+ которая входит в состав пакета "yawl" , разработанного автором.
# http://ibiblio.org/pub/Linux/libs/yawl-0.2.tar.gz
exit 0 # Конец.
bash$ sh agram.sh
islander
isolate
isolead
isotheral
См. также Пример 27-2, Пример 12-18 и Пример A-10.
Для создания блочных комментариев можно использовать "анонимные встроенные документы". См. Пример 17-10.
Попытка вызова утилиты из сценария на машине, где эта утилита отсутствует, потенциально опасна. Для обхода подобных проблем можно воспользоваться утилитой whatis.
CMD=command1 # Основной вариант.
PlanB=command2 # Запасной вариант.
command_test=$(whatis "$CMD" | grep 'nothing appropriate')
# Если 'command1' не найдена в системе, то 'whatis' вернет
#+ "command1: nothing appropriate."
#==> От переводчика: Будьте внимательны! Если у вас локализованная версия whatis
#==> то вывод от нее может отличаться от используемого здесь ('nothing appropriate')
if [[ -z "$command_test" ]] # Проверка наличия утилиты в системе.
then
$CMD option1 option2 # Запуск команды с параметрами.
else # Иначе,
$PlanB #+ запустить command2 (запасной вариант).
fi
Команда run-parts удобна для запуска нескольких сценариев, особенно в комбинации с cron или at.
Было бы неплохо снабдить сценарий графическим интерфейстом X-Window. Для этого можно порекомендовать пакеты Xscript, Xmenu и widtools. Правда, первые два, кажется больше не поддерживаются разработчиками. Зато widtools можно получить здесь.
Пакет widtools (widget tools) требует наличия библиотеки XForms. Кроме того, необходимо слегка подправить Makefile, чтобы этот пакет можно было собрать на типичной Linux-системе. Но хуже всего то, что три из шести виджетов не работают :-(( (segfault).
Для постороения приложений с графическим интерфейсом, можно попробовать Tk, или wish (надстройка над Tcl), PerlTk (Perl с поддержкой Tk), tksh (ksh с поддержкой Tk), XForms4Perl (Perl с поддержкой XForms), Gtk-Perl (Perl с поддержкой Gtk) или PyQt (Python с поддержкой Qt).
33.8. Проблемы безопасности
Уместным будет лишний раз предупредить о соблюдении мер предосторожности при работе с незнакомыми сценариями. Сценарий может содержать червя, трояна или даже вирус. Если вы получили сценарий не из источника, которому доверяете, то никогда не запускайте его с привилегиями root и не позволяйте вставлять его в список сценариев начальной инициализации системы в /etc/rc.d, пока не убедитесь в том, что он безвреден для системы.
Исследователи из Bell Labs и других организаций, включая M. Douglas McIlroy, Tom Duff, и Fred Cohen исследовали вопрос о возможности создания вирусов на языке сценариев командной оболочки, и пришли к выводу, что это делается очень легко и доступно даже для новичков.[ 63 ]
Это еще одна из причин, по которым следует изучать язык командной оболочки. Способность читать и понимать сценарии поможет вам предотвратить возможность взлома и/или разрушения вашей системы.
33.9. Проблемы переносимости
Эта книга делает упор на создании сценариев для командной оболочки Bash, для операционной системы GNU/Linux. Тем не менее, многие рекомендации, приводимые здесь, могут быть вполне применимы и для других командных оболочек, таких как sh и ksh.
Многие версии командных оболочек стремятся следовать стандарту POSIX 1003.2. Вызывая Bash с ключом --posix, или вставляя set -o posix в начало сценария, вы можете заставить Bash очень близко следовать этому стандарту. Но, даже без этого ключа, большинство сценариев, написанных для Bash, будут работать под управлением ksh, и наоборот, т.к. Chet Ramey перенес многие особенности, присущие ksh, в последние версии Bash.
В коммерческих версиях UNIX, сценарии, использующие GNU-версии стандартных утилит и команд, могут оказаться неработоспособными. Однако, с течением времени, таких проблем остается все меньше и меньше, поскольку утилиты GNU, в большинстве своем, заместили свои проприетарные аналоги в UNIX. После того, как Caldera дала разрешение на публикацию исходного кода некоторых версий оригинальных утилит UNIX, этот процесс значительно ускорился.
Bash имеет некоторые особенности, недоступные в традиционном Bourne shell. Среди них:
Некоторые дополнительные ключи вызова
Подстановка команд, с использованием нотации $( )
Некоторые операции над строками
Подстановка процессов
встроенные команды Bash
Более подробный список характерных особенностей Bash, вы найдете в Bash F.A.Q..
33.10. Сценарии командной оболочки под Windows
Даже те пользователи, которые работают в другой, не UNIX-подобной операционной системе, смогут запускать сценарии командной оболочки, а потому -- найти для себя много полезного в этой книге. Пакеты Cygwin от Cygnus, и MKS utilities от Mortice Kern Associates, позволяют дополнить Windows возможностями командной оболочки.
Глава 34. Bash, версия 2
Текущая версия Bash, та, которая скорее всего установлена в вашей системе, фактически -- 2.XX.Y.
bash$ echo $BASH_VERSION
2.05.8(1)-release
В этой версии классического языка сценариев Bash были добавлены переменные-массивы[ 64 ], расширение строк и подстановка параметров, улучшен метод косвенных ссылок на переменные.
Пример 34-1. Расширение строк
#!/bin/bash
# "Расширение" строк (String expansion).
# Введено в Bash, начиная с версии 2.
# Строки вида $'xxx'
# могут содержать дополнительные экранированные символы.
echo $'Звонок звенит 3 раза a a a'
echo $'Три перевода формата f f f'
echo $'10 новых строк nnnnnnnnnn'
exit 0
Пример 34-2. Косвенные ссылки на переменные -- новый метод
#!/bin/bash
# Косвенные ссылки на переменные.
a=letter_of_alphabet
letter_of_alphabet=z
echo "a = $a" # Прямая ссылка.
echo "Now a = ${!a}" # Косвенная ссылка.
# Форма записи ${!variable} намного удобнее старой "eval var1=$$var2"
echo
t=table_cell_3
table_cell_3=24
echo "t = ${!t}" # t = 24
table_cell_3=387
echo "Значение переменной t изменилось на ${!t}" # 387
# Теперь их можно использовать для ссылок на элементы массива,
# или для эмуляции многомерных массивов.
# Было бы здорово, если бы косвенные ссылки допускали индексацию.
exit 0
Пример 34-3. Простая база данных, с применением косвенных ссылок
#!/bin/bash
# resistor-inventory.sh
# Простая база данных, с применением косвенных ссылок.
# ============================================================== #
# Данные
B1723_value=470 # сопротивление (Ом)
B1723_powerdissip=.25 # рассеиваемая мощность (Вт)
B1723_colorcode="желтый-фиолетовый-коричневый" # цветовая маркировка
B1723_loc=173 # где
B1723_inventory=78 # количество (шт)
B1724_value=1000
B1724_powerdissip=.25
B1724_colorcode="коричневый-черный-красный"
B1724_loc=24N
B1724_inventory=243
B1725_value=10000
B1725_powerdissip=.25
B1725_colorcode="коричневый-черный-оранжевый"
B1725_loc=24N
B1725_inventory=89
# ============================================================== #
echo
PS3='Введите ноиер: '
echo
select catalog_number in "B1723" "B1724" "B1725"
do
Inv=${catalog_number}_inventory
Val=${catalog_number}_value
Pdissip=${catalog_number}_powerdissip
Loc=${catalog_number}_loc
Ccode=${catalog_number}_colorcode
echo
echo "Номер по каталогу $catalog_number:"
echo "Имеется в наличии ${!Inv} шт. [${!Val} Ом / ${!Pdissip} Вт]."
echo "Находятся в лотке # ${!Loc}."
echo "Цветовая маркировка: "${!Ccode}"."
break
done
echo; echo
# Упражнение:
# ----------
# Переделайте этот сценарий так, чтобы он использовал массивы вместо косвенных ссылок.
# Какой из вариантов более простой и интуитивный?
# Примечание:
# ----------
# Язык командной оболочки не очень удобен для написания приложений,
#+ работающих с базами данных.
# Для этой цели лучше использовать языки программирования, имеющие
#+ развитые средства для работы со структурами данных,
#+ такие как C++ или Java (может быть Perl).
exit 0
Пример 34-4. Массивы и другие хитрости для раздачи колоды карт в четыре руки
#!/bin/bash
# На старых системах может потребоваться вставить #!/bin/bash2.
# Карты:
# раздача в четыре руки.
UNPICKED=0
PICKED=1
DUPE_CARD=99
LOWER_LIMIT=0