Skip to content

Instantly share code, notes, and snippets.

@codefo
Last active October 6, 2016 16:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codefo/efb27e1a51574340320b9cb3458dfdc1 to your computer and use it in GitHub Desktop.
Save codefo/efb27e1a51574340320b9cb3458dfdc1 to your computer and use it in GitHub Desktop.

Cкрипт вместо считалки

По-моему, запоминать все эти «Лудильщик, портной...» и «Утка, утка, гусь» очень сложно. Зато написать скрипт, который будет делать то же самое, очень просто. Например, на bash. Почему на нем? Ну во-первых, его можно будет использовать практически везде, а во-вторых, я давно уже ничего на нем не писал (от слова «совсем»).

Нет смысла создавать отдельный репозиторий для одного файла, поэтому код буду сохранять прямо тут.

Ну что, поехали?

Сначала добавим файл ttss.sh (аббревиатура от всё той же считалки) в Gist, первой строчкой которого будет shebang:

#!/bin/bash

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

Run ttss.sh

Хаха! Как будто должно было быть что-то другое?!

Запуск с параметрами

Теперь необходимо «научить» скрипт получать список параметров, из которых будет происходить выбор. Естественно, что для этого лучше всего использовать соглашение о синтаксисе аргументов в GNU, поэтому запуск скрипта будет выглядеть так:

$ bash ttss.sh -o Tinker -o Tailor -o Soldier -o Sailor

(-o от option)

Для того, чтобы получить значения параметров, изобретать велосипед не придется, достаточно воспользоваться встроенной в bash командой getopts.

#!/bin/bash

while getopts o: option; do
  case "$option" in
    o) list+=("$OPTARG");;
  esac
done

for value in "${list[@]}"; do
  echo "* $value"
done

Все просто: цикл while будет работать до тех пор, пока команда getopts будет находить флаги -o в переданных параметрах, а значение флага будут добавляться в список с помощью скрытой переменной $OPTARG. Стоит также обратить внимание на знак : в аргументе команды getopts: он указывает на то, что после флага -o может идти его значение.

Запускаем и смотрим на результат:

Run ttss.sh with arguments

Все в порядке!

Случайный выбор

Теперь самое главное: необходимо выбрать случайный вариант из переданных параметров.

#!/bin/bash

while getopts o: option; do
  case "$option" in
    o) list+=("$OPTARG");;
  esac
done

length="${#list[@]}"
index=$(( $RANDOM % $length ))

echo "${list[$index]}"

Для этого достаточно вывести на экран элемент списка c индексом, полученным в результате взятия остатка от деления встроенной функции $RANDOM на длину этого списка.

Run ttss.sh and get random result

Готово!

Небольшое улучшение

Было бы неплохо добавить проверку на минимальное количество вариантов. Ведь выбирать меньше, чем из двух вариантов, не так-то и просто.

#!/bin/bash

while getopts o: option; do
  case "$option" in
    o) list+=("$OPTARG");;
  esac
done

length="${#list[@]}"

if [[ "$length" -lt 2 ]]; then
  >&2 echo -e "Usage: $0 -o <1> -o <2> [-o <n>]\nYou must specify two or more options!"
  exit 42
fi

index=$(( $RANDOM % $length ))

echo "${list[$index]}"

Теперь если пользователь при запуске скрипта передаст менее двух параметров, то увидит сообщение об ошибке, а заодно короткую инструкцию. Разумеется, что в этом случае весь вывод следует перенаправить в stderr воспользовавшись оператором >&2, а скрипт завершить с не нулевым return code.

Run ttss.sh and without arguments and get error

Использование

Необходимо всего-лишь скачать файл скрипта и запустить его:

$ wget https://gist.githubusercontent.com/codefo/efb27e1a51574340320b9cb3458dfdc1/raw/9e7b2880c227836edf9acdf4dbe88ac95097e005/ttss.sh ~/
$ bash ~/ttss.sh -o Tinker -o Tailor -o Soldier -o Sailor

Что почитать?

  1. Bash Reference Manual
  2. Advanced Bash-Scripting Guide, [на русском]
#!/bin/bash
while getopts o: option; do
case "$option" in
o) list+=("$OPTARG");;
esac
done
length="${#list[@]}"
if [[ "$length" -lt 2 ]]; then
>&2 echo -e "Usage: $0 -o <1> -o <2> [-o <n>]\nYou must specify two or more options!"
exit 42
fi
index=$(( $RANDOM % $length ))
echo "${list[$index]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment