Искусство программирования на языке сценариев командной оболочки
Шрифт:
LIMIT=1000 # Простые от 2 до 1000
Primes
{
(( n = $1 + 1 )) # Перейти к следующему числу.
shift # Следующий параметр в списке.
# echo "_n=$n i=$i_"
if (( n == LIMIT ))
then echo $*
return
fi
for i; do # "i" устанавливается в "@", предыдущее значение $n.
# echo "-n=$n i=$i-"
(( i * i > n )) && break #
(( n % i )) && continue # Отсечь составное число с помощью оператора "%".
Primes $n $@ # Рекурсивный вызов внутри цикла.
return
done
Primes $n $@ $n # Рекурсивный вызов за пределами цикла.
# Последовательное накопление позиционных параметров.
# в "$@" накапливаются простые числа.
}
Primes 1
exit 0
# Раскомментарьте строки 16 и 24, это поможет понять суть происходящего.
# Сравните скоростные характеристики этого сценария и сценария (ex68.sh),
# реализующего алгоритм "Решето Эратосфена".
# Упражнение: Попробуйте реализовать этот сценарий без использования рекурсии.
# Это даст некоторый выигрыш в скорости.
+
Jordi Sanfeliu дал согласие на публикацию своего сценария tree.
Пример A-19. tree: Вывод дерева каталогов
#!/bin/sh
# @(#) tree 1.1 30/11/95 by Jordi Sanfeliu
# email: mikaku@fiwix.org
#
# Начальная версия: 1.0 30/11/95
# Следующая версия: 1.1 24/02/97 Now, with symbolic links
# Исправления : Ian Kjos, поддержка недоступных каталогов
# email: beth13@mail.utexas.edu
#
# Tree -- средство просмотра дерева каталогов (очевидно :-) )
#
# ==> Используется в данном документе с разрешения автора сценария, Jordi Sanfeliu.
# ==> Комментарии, добавленные автором документа.
# ==> Добавлено "окавычивание" аргументов.
search {
for dir in `echo *`
# ==> `echo *` список всех файлов в текущем каталоге, без символов перевода строки.
# ==> Тот же эффект дает for dir in *
# ==> но "dir in `echo *`" не обрабатывет файлы, чьи имена содержат пробелы.
do
if [ -d "$dir" ] ; then # ==> Если это каталог (-d)...
zz=0 # ==> Временная переменная, для сохранения уровня вложенности каталога.
while [ $zz != $deep ] # Keep track of inner nested loop.
do
echo -n "| " # ==> Показать символ вертикальной связи,
# ==>
zz=`expr $zz + 1` # ==> Нарастить zz.
done
if [ -L "$dir" ] ; then # ==> Если символическая ссылка на каталог...
echo "+---$dir" `ls -l $dir | sed 's/^.*'$dir' //'`
# ==> Показать горизонтальный соединитель и имя связянного каталога, но...
# ==> без указания даты/времени.
else
echo "+---$dir" # ==> Вывести горизонтальный соединитель...
# ==> и название каталога.
if cd "$dir" ; then # ==> Если можно войти в каталог...
deep=`expr $deep + 1` # ==> Нарастить уровень вложенности.
search # рекурсия ;-)
numdirs=`expr $numdirs + 1` # ==> Нарастить счетчик каталогов.
fi
fi
fi
done
cd .. # ==> Подняться на один уровень вверх.
if [ "$deep" ] ; then # ==> Если depth = 0 (возвращает TRUE)...
swfi=1 # ==> выставить признак окончания поиска.
fi
deep=`expr $deep - 1` # ==> Уменьшить уровень вложенности.
}
# - Main -
if [ $# = 0 ] ; then
cd `pwd` # ==> Если аргумент командной строки отсутствует, то используется текущий каталог.
else
cd $1 # ==> иначе перейти в заданный каталог.
fi
echo "Начальный каталог = `pwd`"
swfi=0 # ==> Признак завершения поиска.
deep=0 # ==> Уровень вложенности.
numdirs=0
zz=0
while [ "$swfi" != 1 ] # Пока поиск не закончен...
do
search # ==> Вызвать функцию поиска.
done
echo "Всего каталогов = $numdirs"
exit 0
# ==> Попробуйте разобраться в том как этот сценарий работает.
Noah Friedman дал разрешение на публикацию своей библиотеки функций для работы со строками, которая, по сути, воспроизводит некоторые библиотечные функции языка C.
Пример A-20. Функции для работы со строками
#!/bin/bash
# string.bash --- эмуляция библиотеки функций string(3)
# Автор: Noah Friedman <friedman@prep.ai.mit.edu>
# ==> Используется с его разрешения.
# Дата создания: 1992-07-01
# Дата последней модификации: 1993-09-29
# Public domain
# Преобразование в синтаксис bash v2 выполнил Chet Ramey
# Комментарий:
# Код:
#:docstring strcat:
# Порядок использования: strcat s1 s2