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

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Мендель Купер, "Искусство программирования на языке сценариев командной оболочки" бесплатно, без регистрации.
Перейти на страницу:

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

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*