Выбрать главу

··guess=0····················# Число, предложенное игроком

··guesses=0··················# Количество попыток

··number=$(($$ % $biggest) # Случайное число от 1 до $biggest

··echo "Guess a number between 1 and $biggest"

··while ["$guess" −ne $number]; do

····/bin/echo −n "Guess?"; read answer

····if ["$guess" −lt $number]; then

······echo"… bigger!"

····elif ["$guess" −gt $number]; then

······echo"… smaller!

····fi

····guesses=$(($guesses + 1))

··done

··echo "Right!! Guessed $number in $guesses guesses."

··exit 0

Как это работает

Чтобы было понятнее, как происходит получение случайного числа в , напомним, что специальная переменная $$ хранит числовой идентификатор процесса (Process ID, PID) командной оболочки, в которой выполняется сценарий. Обычно это 5- или 6-значное число. При каждом запуске сценарий получает новый PID. Последовательность % $biggest делит значение PID на заданное наибольшее значение и возвращает остаток. Иными словами, 5 % 4 = = 1, так же как 41 % 4. Это простой способ получения псевдослучайных чисел в диапазоне от 1 до $biggest.

Запуск сценария

Отлаживая игру, прежде всего проверим и убедимся, что генерируемое число достаточно случайно. Для этого получим PID оболочки, в которой выполняется сценарий, и приведем его к требуемому диапазону, используя операцию % извлечения остатка от деления нацело . Для проверки операции введите в командной строке следующие команды:

$ echo $(($$ % 100))

5

$ echo $(($$ % 100))

5

$ echo $(($$ % 100))

5

Операция работает, но числа не выглядят случайными. Если немного поразмыслить, становится понятно, почему так происходит: когда команда выполняется непосредственно в командной строке, она всегда получает одно и то же значение PID; но внутри сценария команда каждый раз будет выполняться в другой подоболочке, с другим значением PID.

Еще один способ получить случайное число — воспользоваться переменной окружения $RANDOM. Это не простая переменная! При каждом обращении к ней вы будете получать разные значения. Чтобы получить число в диапазоне от 1 до $biggest, используйте в строке выражение $(($RANDOM % $biggest + 1)).

Следующий шаг — добавление основной логики игры. В генерируется случайное число в диапазоне от 1 до 100; в пользователь делает попытку угадать это число; затем пользователю сообщается, что число слишком большое или слишком маленькое , пока он наконец не угадает правильное значение. После ввода всего основного кода можно попробовать запустить сценарий и посмотреть, как он работает. Ниже демонстрируется проверка работы сценария из листинга 1.30:

$ hilow

./013-hilow.sh: line 19: unexpected EOF while looking for matching '"’

./013-hilow.sh: line 22: syntax error: unexpected end of file

Опля! Мы столкнулись с проклятием разработчиков сценариев: неожиданный конец файла (EOF). Сообщение говорит, что ошибка находится в строке 19, но это не означает, что она действительно там. На самом деле строка 19 не содержит ошибок:

$ sed −n 19p hilow

echo "Right!! Guessed $number in $guesses guesses."

Чтобы понять причину ошибки, вспомните, что строки в кавычках могут содержать символы перевода строки. То есть, встретив кавычки, по ошибке не закрытые как следует, командная оболочка просто продолжит читать сценарий, стараясь найти парную закрывающую кавычку, и останавливается, только встретив самую последнюю и обнаружив, что в сценарии что-то неправильно.

Следовательно, проблема должна находиться где-то выше. В сообщении об ошибке есть единственная полезная деталь — оно указывает, какой символ не был найден. То есть можно попробовать с помощью grep извлечь все строки, содержащие кавычки, и затем отфильтровать те из них, что содержат по две кавычки, как показано ниже:

$ grep '"' 013-hilow.sh | egrep −v '.*".*".*'

echo"… smaller!

Вот и все! В строке , сообщающей, что число, предложенное пользователем, слишком мало, отсутствует закрывающая кавычка. Добавим ее в конец строки и повторим попытку запустить сценарий:

$ hilow

./013-hilow.sh: line 7: unexpected EOF while looking for matching ')’

./013-hilow.sh: line 22: syntax error: unexpected end of file

Не вышло. Еще одна проблема. Выражений в круглых скобках в сценарии немного, поэтому мы можем просто посмотреть и увидеть, что в выражении, вычисляющем случайное число, отсутствует закрывающая скобка: