Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программирование » Искусство программирования на языке сценариев командной оболочки - Мендель Купер

Искусство программирования на языке сценариев командной оболочки - Мендель Купер

Читать онлайн Искусство программирования на языке сценариев командной оболочки - Мендель Купер

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 79 80 81 82 83 84 85 86 87 ... 96
Перейти на страницу:

if [ "$1" -lt "$lower_limit" -o "$1" -gt "$upper_limit" ]

then

return $FALSE # Выход за границы массива.

fi

row=$2

let "left = $row * $ROWS" # Левая граница.

let "right = $left + $COLS - 1" # Правая граница.

if [ "$1" -lt "$left" -o "$1" -gt "$right" ]

then

return $FALSE # Выхол за нижнюю строку.

fi

return $TRUE # Координаты корректны.

}

IsAlive () # Проверка наличия "живой" особи в ячейке.

# Принимает массив и номер ячейки в качестве входных аргументов.

{

GetCount "$1" $2 # Подсчитать кол-во "живых" соседей.

local nhbd=$?

if [ "$nhbd" -eq "$BIRTH" ] # "Живая".

then

return $ALIVE

fi

if [ "$3" = "." -a "$nhbd" -eq "$SURVIVE" ]

then # "Живая" если перед этим была "живая".

return $ALIVE

fi

return $DEAD # По-умолчанию.

}

GetCount () # Подсчет "живых" соседей.

# Необходимо 2 аргумента:

# $1) переменная-массив

# $2) cell номер ячейки

{

local cell_number=$2

local array

local top

local center

local bottom

local r

local row

local i

local t_top

local t_cen

local t_bot

local count=0

local ROW_NHBD=3

array=( `echo "$1"` )

let "top = $cell_number - $COLS - 1" # Номера соседних ячеек.

let "center = $cell_number - 1"

let "bottom = $cell_number + $COLS - 1"

let "r = $cell_number / $ROWS"

for ((i=0; i<$ROW_NHBD; i++)) # Просмотр слева-направо.

do

let "t_top = $top + $i"

let "t_cen = $center + $i"

let "t_bot = $bottom + $i"

let "row = $r" # Пройти по соседям в средней строке.

IsValid $t_cen $row # Координаты корректны?

if [ $? -eq "$TRUE" ]

then

if [ ${array[$t_cen]} = "$ALIVE1" ] # "Живая"?

then # Да!

let "count += 1" # Нарастить счетчик.

fi

fi

let "row = $r - 1" # По верхней строке.

IsValid $t_top $row

if [ $? -eq "$TRUE" ]

then

if [ ${array[$t_top]} = "$ALIVE1" ]

then

let "count += 1"

fi

fi

let "row = $r + 1" # По нижней строке.

IsValid $t_bot $row

if [ $? -eq "$TRUE" ]

then

if [ ${array[$t_bot]} = "$ALIVE1" ]

then

let "count += 1"

fi

fi

done

if [ ${array[$cell_number]} = "$ALIVE1" ]

then

let "count -= 1" # Убедиться, что сама проверяемая ячейка

fi #+ не была подсчитана.

return $count

}

next_gen () # Обновить массив, в котором содержится информация о новом "поколении".

{

local array

local i=0

array=( `echo "$1"` ) # Преобразовать в массив.

while [ "$i" -lt "$cells" ]

do

IsAlive "$1" $i ${array[$i]} # "Живая"?

if [ $? -eq "$ALIVE" ]

then # Если "живая", то

array[$i]=. #+ записать точку.

else

array[$i]="_" # Иначе -- символ подчеркивания

fi #+ (который позднее заменится на пробел).

let "i += 1"

done

# let "generation += 1" # Увеличить счетчик поколений.

# Подготовка переменных, для передачи в функцию "display".

avar=`echo ${array[@]}` # Преобразовать массив в строку.

display "$avar" # Вывести его.

echo; echo

echo "Поколение $generation -- живых особей $alive"

if [ "$alive" -eq 0 ]

then

echo

echo "Преждеверменное завершение: не осталось ни одной живой особи!"

exit $NONE_ALIVE # Нет смысла продолжать

fi #+ если не осталось ни одной живой особи

}

# =========================================================

# main ()

# Загрузить начальное поколение из файла.

initial=( `cat "$startfile" | sed -e '/#/d' | tr -d 'n' |

sed -e 's/./. /g' -e 's/_/_ /g'` )

# Удалить строки, начинающиеся с символа '#' -- комментарии.

# Удалить строки перевода строки и вставить пробелы между элементами.

clear # Очистка экрана.

echo # Заголовок

echo "======================="

echo " $GENERATIONS поколений"

echo " в"

echo " игре " ЖИЗНЬ""

echo "======================="

# -------- Вывести первое поколение. --------

Gen0=`echo ${initial[@]}`

display "$Gen0" # Тлько вывод.

echo; echo

echo "Поколение $generation -- живых особей $alive"

# -------------------------------------------

let "generation += 1" # Нарастить счетчик поколений.

echo

# ------- Вывести второе поколение. -------

Cur=`echo ${initial[@]}`

next_gen "$Cur" # Обновить и вывести.

# ------------------------------------------

let "generation += 1" # Нарастить счетчик поколений.

# ------ Основной цикл игры ------

while [ "$generation" -le "$GENERATIONS" ]

do

Cur="$avar"

next_gen "$Cur"

let "generation += 1"

done

# ==============================================================

echo

exit 0

# --------------------------------------------------------------

# Этот сценарий имеет недоработку.

# Граничные ячейки сверху, снизу и сбоков остаются пустыми.

# Упражнение: Доработайте сценарий таким образом, чтобы ,

# + левая и правая стороны как бы "соприкасались",

# + так же и верхняя и нижняя стороны.

Пример A-12. Файл с первым поколением для игры "Жизнь"

# Это файл-пример, содержащий "поколение 0", для сценария "life.sh".

# --------------------------------------------------------------

# Игровое поле имеет размер 10 x 10, точкой обозначается "живая" особь,

#+ символом подчеркивания -- пустая ячейка. Мы не можем использовать пробелы,

#+ для обозначения пустых ячеек, из-за особенностей строения массивов в Bash.

# [Упражнение для читателей: объясните, почему?.]

#

# Строки, начинающиеся с символа '#' считаются комментариями, сценарий их игнорирует.

__.__..___

___._.____

____.___..

_._______.

____._____

..__...___

____._____

___...____

__.._..___

_..___..__

+++

Следующие два сценария предоставил Mark Moraes, из университета в Торонто. См. файл "Moraes-COPYRIGHT", который содержит указание на авторские права.

Пример A-13. behead: Удаление заголовков из электронных писем и новостей

#! /bin/sh

# Удаление заголовков из электронных писем и новостей т.е. до первой

# пустой строки

# Mark Moraes, Университет в Торонто

# ==> Такие комментарии добавлены автором документа.

if [ $# -eq 0 ]; then

# ==> Если входной аргумент не задан (файл), то выводить результат на stdin.

sed -e '1,/^$/d' -e '/^[ ]*$/d'

# --> Удалить пустые строки и все строки предшествующие им

else

# ==> Если аргумент командной строки задан, то использовать его как имя файла.

for i do

sed -e '1,/^$/d' -e '/^[ ]*$/d' $i

# --> То же, что и выше.

done

fi

# ==> Упражнение: Добавьте проверку на наличие ошибок.

# ==>

# ==> Обратите внимание -- как похожи маленькие сценарии sed, за исключением передачи аргумента.

# ==> Можно ли его оформит в виде функции? Почему да или почему нет?

Пример A-14. ftpget: Скачивание файлов по ftp

#! /bin/sh

# $Id: ftpget,v 1.2 91/05/07 21:15:43 moraes Exp $

# Сценарий устанавливает анонимное соединение с ftp-сервером.

# Простой и быстрый - написан как дополнение к ftplist

# -h -- удаленный сервер (по-умолчанию prep.ai.mit.edu)

# -d -- каталог на сервере - вы можете указать последовательность из нескольких ключей -d

# Если вы используете относительные пути,

# будьте внимательны при задании последовательности.

# (по-умолчанию -- каталог пользователя ftp)

# -v -- "многословный" режим, будет показывать все ответы ftp-сервера

# -f -- file[:localfile] скачивает удаленный file и записывает под именем localfile

# -m -- шаблон для mget. Не забудьте взять в кавычки!

# -c -- локальный каталог

# Например,

# ftpget -h expo.lcs.mit.edu -d contrib -f xplaces.shar:xplaces.sh

# -d ../pub/R3/fixes -c ~/fixes -m 'fix*'

# Эта команда загрузит файл xplaces.shar из ~ftp/contrib с expo.lcs.mit.edu

# и сохранит под именем xplaces.sh в текущем каталоге, затем заберет все исправления (fixes)

# из ~ftp/pub/R3/fixes и поместит их в каталог ~/fixes.

# Очевидно, что последовательность ключей и аргументов очень важна, поскольку

# она определяет последовательность операций, выполняемых с удаленным ftp-сервером

#

# Mark Moraes ([email protected]), Feb 1, 1989

#

# ==> Эти комментарии добавлены автором документа.

# PATH=/local/bin:/usr/ucb:/usr/bin:/bin

# export PATH

# ==> Первые две строки в оригинальном сценарии вероятно излишни.

TMPFILE=/tmp/ftp.$$

# ==> Создан временный файл

SITE=`domainname`.toronto.edu

# ==> 'domainname' подобен 'hostname'

usage="Порядок использования: $0 [-h удаленный_сервер] [-d удаленный_каталог]... [-f удаленный_файл:локальный_файл]...

[-c локальный_каталог] [-m шаблон_имен_файлов] [-v]"

ftpflags="-i -n"

verbflag=

set -f # разрешить подстановку имен файлов (globbing) для опции -m

set x `getopt vh:d:c:m:f: $*`

if [ $? != 0 ]; then

echo $usage

exit 65

fi

shift

trap 'rm -f ${TMPFILE} ; exit' 0 1 2 3 15

echo "user anonymous ${USER-gnu}@${SITE} > ${TMPFILE}"

# ==> Добавлены кавычки (рекомендуется).

echo binary >> ${TMPFILE}

for i in $* # ==> Разбор командной строки.

do

case $i in

-v) verbflag=-v; echo hash >> ${TMPFILE}; shift;;

-h) remhost=$2; shift 2;;

-d) echo cd $2 >> ${TMPFILE};

if [ x${verbflag} != x ]; then

echo pwd >> ${TMPFILE};

fi;

shift 2;;

-c) echo lcd $2 >> ${TMPFILE}; shift 2;;

-m) echo mget "$2" >> ${TMPFILE}; shift 2;;

-f) f1=`expr "$2" : "([^:]*).*"`; f2=`expr "$2" : "[^:]*:(.*)"`;

echo get ${f1} ${f2} >> ${TMPFILE}; shift 2;;

--) shift; break;;

esac

done

if [ $# -ne 0 ]; then

1 ... 79 80 81 82 83 84 85 86 87 ... 96
Перейти на страницу:
Тут вы можете бесплатно читать книгу Искусство программирования на языке сценариев командной оболочки - Мендель Купер.
Комментарии