Дейв Тейлор - Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание
- Название:Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание
- Автор:
- Жанр:
- Издательство:Питер
- Год:2017
- Город:СПб.
- ISBN:978-5-496-03029-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дейв Тейлор - Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание краткое содержание
Цель этой книги — продемонстрировать практические приемы программирования сценариев на bash и познакомить с самыми распространенными утилитами на коротких и компактных примерах, не вдаваясь в излишние подробности. Экспериментируйте с этими сценариями — ломайте, исправляйте и приспосабливайте их под свои нужды, чтобы понять, как они работают. Только так вы сможете решать самые сложные задачи.
Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Несмотря на то что эта игра написана для столиц штатов, ее легко переделать для работы с любыми парами данных. Например, создать отдельный файл для Италии, с соответствиями страна/валюта или политик/партия. Как мы не раз видели в Unix, достаточно универсальные сценарии порой можно использовать совершенно неожиданными и непредусмотренными ранее способами.
№ 86. Является ли число простым?
Простыми называют числа, которые делятся без остатка только на самих себя, например 7. С другой стороны, 6 и 8 не являются простыми числами. Простые однозначные числа распознаются легко, но с большими приходится попотеть.
В математике имеется несколько приемов определения простых чисел, но мы воспользуемся методом простого перебора и будем пытаться применить все возможные делители, сравнивая остаток от деления с нулем, как показано в листинге 12.7.
Код
Листинг 12.7.Сценарий isprime
··#!/bin/bash
··# isprime — получает число и проверяет, является ли оно простым.
··#·· Использует прием, известный как пробное деление: просто перебирает
··#·· числа от 2 до (n/2) и пытается использовать их в качестве делителя,
··#·· проверяя остаток от деления.
··counter=2
··remainder=1
··if [$# −eq 0]; then
····echo "Usage: isprime NUMBER" >&2
····exit 1
··fi
··number=$1
··# 3 и 2 — простые числа, 1 — нет.
··if [$number −lt 2]; then
····echo "No, $number is not a prime"
····exit 0
··fi
··# Теперь выполним некоторые вычисления.
·· while [$counter −le $(expr $number / −a— a $remainder −ne 0]
··do
····remainder=$(expr $number % $counter) # '/’ деление, '%' остаток
····# echo " for counter $counter, remainder = $remainder"
····counter=$(expr $counter + 1)
··done
··if [$remainder −eq 0]; then
····echo "No, $number is not a prime"
··else
····echo "Yes, $number is a prime"
··fi
··exit 0
Как это работает
Основу сценария составляет цикл while , поэтому уделим ему основное внимание. Для числа 77 условное выражение в заголовке цикла приняло бы вид:
while [2 −le 38 −a 1 −ne 0]
Очевидно, что оно не выполняется: 77 не делится нацело на 2. Каждый раз, когда код проверяет потенциальный делитель ($counter) и обнаруживает, что исходное число не делится на него нацело, он вычисляет остаток ($number % $counter), увеличивает $counter на 1 и повторяет вычисления.
Запуск сценария
Давайте выберем несколько чисел, которые на первый взгляд кажутся простыми, и проверим их, как показано в листинге 12.8.
Листинг 12.8.Опробование сценария isprime с несколькими числами
$ isprime 77
No, 77 is not a prime
$ isprime 771
No, 771 is not a prime
$ isprime 701
Yes, 701 is a prime
Если вам любопытно, раскомментируйте команду echo в цикле while, чтобы увидеть, как выполняются вычисления, и получить представление, насколько быстро или медленно сценарий находит делитель, делящий число нацело, без остатка. В листинге 12.9 показано, что в этом случае получается при попытке проверить число 77.
Результаты
Листинг 12.9.Запуск сценария с раскомментированной отладочной строкой
$ isprime 77
··for counter 2, remainder = 1
··for counter 3, remainder = 2
··for counter 4, remainder = 1
··for counter 5, remainder = 2
··for counter 6, remainder = 5
··for counter 7, remainder = 0
No, 77 is not a prime
Усовершенствование сценария
Сценарий реализует не самый эффективный алгоритм проверки числа, который работает тем медленнее, чем больше число. Например, взгляните на условие в цикле while. Сценарий раз за разом продолжает вычислять выражение $(expr $number / 2), тогда как его можно было вычислить только один раз и использовать вычисленное значение во всех последующих итерациях, сэкономив время на запуске подоболочки и вызове команды expr для вычисления значения, которое не изменяется ни на йоту до самой последней итерации.
Существуют также другие, не такие примитивные способы проверки простых чисел, включая замечательный алгоритм с интересным названием «Решето Эратосфена», более современный алгоритм «Решето Сундарама» или более сложный — «Решето Аткина». Поищите их описания в Интернете и проверьте с их помощью номер своего телефона (без дефисов!).
№ 87. Игральные кости
Это удобный сценарий для всех, кто любит играть в настольные игры, особенно ролевые, такие как Dungeons & Dragons .
В таких играх обычно бросаются кости, это может быть и один двадцатигранник, и шесть шестигранников, но в любом случае процесс основан на вероятностях. Игральные кости — по сути, простейший генератор случайных чисел, независимо от того, сколько таких генераторов задействовано в игре: один, два ( Monopoly или Trouble ) или больше.
Все эти случаи, как оказывается, легко смоделировать, что и делает сценарий в листинге 12.10, позволяющий указать количество и тип костей и затем «бросающий» их и возвращающий сумму.
Код
Листинг 12.10.Сценарий rolldice
#!/bin/bash
# rolldice — анализирует количество и тип костей и имитирует их броски.
#·· Примеры: d6 = один шестигранник
#············2d12 = два двенадцатигранника у каждого
#············d4 3d8 2d20 = один четырехгранник, три восьмигранника
#··························и два двадцатигранника.
rolldie()
{
··dice=$1
··dicecount=1
··sum=0
··# Первый шаг: представить аргумент в формате MdN.
·· if [-z "$(echo $dice | grep 'd')"]; then
····quantity=1
····sides=$dice
··else
····quantity=$(echo $dice |
cut −f— f1)
····if [-z "$quantity"]; then # Пользователь указал dN, а не просто N.
······quantity=1
····fi
····sides=$(echo $dice | cut −dd −f2)
··fi
··echo ""; echo "rolling $quantity $sides-sided die"
··# Бросить кубик…
··while [$dicecount −le $quantity]; do
···· roll=$((($RANDOM % $sides) + 1))
····sum=$(($sum + $roll))
····echo " roll #$dicecount = $roll"
····dicecount=$(($dicecount + 1))
··done
··echo "I rolled $dice and it added up to $sum"
}
while [$# −gt 0]; do
··rolldie $1
··sumtotal=$(($sumtotal + $sum))
··shift
done
echo ""
echo "In total, all of those dice add up to $sumtotal"
echo ""
exit 0
Как это работает
Сценарий вращается вокруг простой строки кода, которая вызывает генератор случайных чисел оболочки bash, используя говорящую ссылку $RANDOM . Это ключевая строка в сценарии, всё остальное лишь внешнее оформление.
Интервал:
Закладка: