Простой интерактив в bash-скриптах
Иногда полезно иметь в своих скриптах элемент интерактивного взаимодействия с пользователем, например, запросить с клавиатуры некую строку (путь, пароль, имя пользователя и т.д.), или получить от пользователя подтверждение действия (
Вы уверены? [Y/n]
). Далее покажу простейшие случаи.Все, кто хоть раз пользовался для создания нового пользователя скриптом
adduser
, наблюдали на экране следующую картину:Login name for new user []: wolfkid
User ID ('UID') [ defaults to next available ]:
Initial group [ users ]:
...
Home directory [ /home/wolfkid ]
Shell [ /bin/bash ]
Expiry date (YYYY-MM-DD) []:
Понятно, что где-то можно (и нужно) ввести свои данные, а где-то согласиться с предлагаемыми скриптом по умолчанию (или не согласиться, ввести свое).
Вопрос, как такое сделать в своем скрипте?
В данном случае можно воспользоваться командой
read
.Общий синтаксис:
read [ПАРАМЕТРЫ] [ПЕРЕМЕННАЯ]
Если имя переменной не будет указано, то, что было введено с клавиатуры попадет в специальную переменную
$REPLY
.Обратите внимание: в команду
read
имя переменной подставляется без символа $
. Т.е. если вы хотите, чтоб введенная строка оказалась в переменной VAR1
, то синтаксис такой:read VAR1
Напишем функцию, которая будет принимать два параметра - строку с пояснением, что мы хотим, чтоб пользователь ввел, и строку, которая будет представлять значение по умолчанию. В случае, если пользователь что-то ввел, то функция запишет в переменную
$STR_RESULT
новое значение. Если же пользователь просто нажмет Enter, то в $STR_RESULT
будет записано значение, переданное во втором параметре.ask_string() #1-user ask string, #2-default variant
{
read -r -p "$1 [$2]:"
if [ -z "$REPLY" ]; then
if [ -n "$2" ]; then
STR_RESULT=$2
fi
else
STR_RESULT=$REPLY
fi
}
Небольшое пояснение по используемым параметрам
read
:-r
- отключает режим интерпретации эскейп-последовательностей, т.е. \n
, \r
, \t
и т.д. не будут записаны в переменную, как символы возврата каретки, перевода строки или табуляции, а будут восприниматься, как символьные последовательности - слэш и буква.-p [СООБЩЕНИЕ]
- СООБЩЕНИЕ
, это строка, которая будет выведена пользователю перед тем, как он сможет ввести данные.Пример вызова функции:
ask_string "Select path" "/home/smallwolfie/test/testdir"
echo $STR_RESULT
Вывод:
Пользователь нажал Enter, оставив значение по умолчанию:
smallwolfie@wolfschanze:~/test/input01$ ./askstring
Select path [/home/smallwolfie/test/testdir]:
/home/smallwolfie/test/testdir
Пользователь ввел другое значение:
smallwolfie@wolfschanze:~/test/input01$ ./askstring
Select path [/home/smallwolfie/test/testdir]:/tmp
/tmp
Готовый скрипт на GitHub
Готовый скрипт на PasteBin
Обычный запрос
Вы уверены [Y/N]
. Для удобства использования (т.е. копипаста в другие скрипты) тоже можно реализовать в виде отдельной функции, которой передается один параметр - строка с вопросом для пользователя:ask_y_n() #$1 - question
{
echo -n "$1 [Y/N]: "
while [ 1 -eq 1 ];do
read -s -n1
case "$REPLY" in
[yY])
echo
return 0
;;
[nN])
echo
return 1
;;
esac
done
}
Пояснения:
1. Командой
echo -n "$1 [Y/N]: "
выводим пользователю сообщение с пояснением, что надо нажать (Y
или N
). Параметр -n
в команде echo
запрещает ей переводить курсор на новую строку. Опцией -p
команды read
не пользуемся для красоты, иначе сообщение будет выскакивать при каждом нажатии клавиши, и заполнять экран.2. Организуем бесконечный цикл:
while [ 1 -eq 1 ];do
#...
done
Единица всегда равна единице, поэтому цикл не завершится, если не будет какого-то прерывания внутри цикла.
3. В начале цикла вставляем команду
read
со следующими параметрами:-s
- не отображать вводимые пользователем символы на экране-n1
- читать 1 символ, и завершаться, не дожидаясь нажатия клавиши Enter.4. Далее в операторе
case
проверяем, что было нажато: если Y
или y
, то пользователь ответил "да", если N
или n
- "нет". Ну не заставлять же пользователя регистр символов отдельно проверять... Возвращаем соответствующий код возврата 0
для "да", 1
для "нет"Пример вызова функции:
ask_y_n "Run it?"
if [ "$?" -eq 0 ];then
echo "User replied YES!"
else
echo "User replied NO :("
fi
Вывод:
Пользователь не нажал ничего, или нажал что-нибудь кроме
YyNn
:smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:
Пользователь ответил "Нет":
smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:
User replied NO :(
Пользователь ответил "Да":
smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:
User replied YES :)
Скрипт на GitHub
Скрипт на PasteBin
Внутренние команды bash
Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2019/05/11/pros