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