Когда вы устанавливаете новые программы в терминале, вы могли часто видеть появляющиеся информативные диалоговые блоки для обратной связи с вами. Типы диалоговых блоков различны: от простых диалогов да/нет до полей ввода, блоков паролей, чеклистов, меню и так далее. Преимущества использования таких дружественных к пользователю блоков очевидны, ведь они интуитивно направляют вас для ввода необходимой информации.
Когда вы пишите интерактивный шелл скрипт, вы на самом деле можете использовать такие диалоговые блоки для принятия ввода пользователя. Будучи предварительно установленной на всех современных дистрибутивах Linux, программа под названием whiptail может упростить процесс создания шелл скриптом диалоговых и информационных блоков в терминале наподобие тех, что графических интерфейсов, что кодируют Zenity или Xdialog для скриптов.
В этом уроке я опишу как с использованием whiptail создать дружественный пользователю диалоговые блоки в шел скрипте. Я также покажу Баш фрагменты кода различных диалоговых блоков, поддерживаемых в whiptail.
Создаём блок с сообщением
Блок с сообщением показывает произвольный текст с кнопкой подтверждения для продолжения.
whiptail --title "<название бокса>" --msgbox "<текст для показа>" <высота> <ширина>
Пример:
#!/bin/bash whiptail --title "Бокс с сообщением" --msgbox "Создаём информационный блок с whiptail. Нажмите Ok для продолжения." 10 60
Создание Да/Нет блоков
Одним из частных пользовательских вводов является Да или Нет. В этом случае может быть использован диалоговый блок Да/Нет.
whiptail --title "<название диалогового блока>" --yesno "<текст для показа>" <высота> <ширина>
Пример:
#!/bin/bash if (whiptail --title "Пробуем блок Да/Нет" --yesno "Выберите между Да или Нет." 10 60) then echo "Вы выбрали Да. Статус выхода был $?." else echo "Вы выбрали нет. Статус выхода был $?." fi
Опционально вы можете настроить текст кнопок Да и Нет с помощью опций "--yes-button" and "--no-button"
Например:
#!/bin/bash if (whiptail --title "Тестируем блок Да/Нет" --yes-button "Кола" --no-button "Пепси" --yesno "Что вам нравится больше?" 10 60) then echo "Вы выбрали Колу. Статус выхода был $?." else echo "Вы выбрали Пепси. Статус выхода был $?." fi
Создаём блок свободного ввода
Если вы хотите принять любой произвольный текст от пользователя, вы можете использовать этот блок ввода
whiptail --title "<Название блока ввода>" --inputbox "<Текст для показа>" <высота> <ширина> <текст по умолчанию>
Например:
#!/bin/bash PET=$(whiptail --title "Тестируем поле ввода" --inputbox "Как зовут твоё домашнее животное?" 10 60 Машка 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus = 0 ]; then echo "Имя твоего домашнего животного:" $PET else echo "Ты выбрал отмену." fi
Создание блока для ввода пароля
Блок пароля полезен, когда вы хотите получить чувствительную информацию от пользователя.
whiptail --title "<Название блока пароля>" --passwordbox "<текст для отображения>" <высота> <ширина>
Пример:
#!/bin/bash PASSWORD=$(whiptail --title "Теста блока пароля" --passwordbox "Введите ваш пароль и нажмите ОК для продолжения." 10 60 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus = 0 ]; then echo "Ваш пароль:" $PASSWORD else echo "Вы выбрали отмену." fi
Создание меню
Когда вы хотите спросить пользователя выбрать один из нескольких произвольных вариантов, вы можете использовать меню.
whiptail --title "<название меню>" --menu "<текст для отображения>" <высота> <ширина> <опции меню> [ ] . . .
Пример:
#!/bin/bash OPTION=$(whiptail --title "Пробуем меню" --menu "Сделайте ваш выбор" 15 60 4 \ "1" "Острые сосиски на гриле" \ "2" "Сырные Халлуми на гриле" \ "3" "Куриные крылышки" \ "4" "Салат из жареных баклажанов" 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus = 0 ]; then echo "Вы выбрали:" $OPTION else echo "Вы нажали отмену." fi
Создание диалога радиолист
Блок радиолист схож по смыслу с меню в том смысле, что вы можете выбрать только одну опцию из списка доступных опций. В отличие от блока меню, тем не менее, вы можете отобразить, какая опция выбрана по умолчанию, определив её статус.
whiptail --title "<заголовок радиолиста>" --radiolist "<текст для показа>" <высота> <ширина> <опции списка> [ ] . . .
Например:
#!/bin/bash DISTROS=$(whiptail --title "Тестируем чеклист" --radiolist \ "Какой дистрибутив Линукс вы выбираете?" 15 60 4 \ "debian" "Почтенный Debian" ON \ "ubuntu" "Популярный Ubuntu" OFF \ "centos" "Стабильный CentOS" OFF \ "mint" "Восходящая звезда Mint" OFF 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus = 0 ]; then echo "Выбранный дистрибутив:"$DISTROS else echo "Вы нажали отмену." fi
Создаём диалок чеклиста
Чеклист полезен, когда вы хотите попросить пользователя выбрать более чем один вариант из списка опций, он отличается от радиолиста, в котором можно сделать только один выбор.
whiptail --title "<заголовок чеклиста>" --checklist "<текст для показа>" <высота> <ширина> <опции списка> [ ] . . .
Пример:
#!/bin/bash DISTROS=$(whiptail --title "Тестируем чеклист" --checklist \ "Выберите предпочитаемый дистрибутив Линукс" 15 60 4 \ "debian" "Почтенный Debian" ON \ "ubuntu" "Популярная Ubuntu" OFF \ "centos" "Стабильная CentOS" ON \ "mint" "Восходящая звезда Mint" OFF 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus = 0 ]; then echo "Ваш любимый дистрибутив:" $DISTROS else echo "Вы выбрали отмену." fi
Сооздание строки прогресса
Другой дружественный пользователю диалоговый блок это прогресс бар. whiptail читает из стандартного ввода проценты (от 0 до 100) и отображает соответствующий индикатор датчика.
whiptail --gauge "<текст для отображения>" <высота> <ширина> <начальный процент>
Пример:
#!/bin/bash { for ((i = 0 ; i <= 100 ; i+=20)); do sleep 1 echo $i done } | whiptail --gauge "Please wait while installing" 6 60 0
Теперь вы увидели, как легко создавать полезные диалоговые блоки в интерактивных шелл скриптах. В следующий раз, когда вам понадобиться написать шелл скрипт для кого-то, почему бы не попробовать whiptail и не впечатлить его или её? 🙂
п.с. Все примеры, кроме последнего, одинаково хорошо работают и в bash, и в sh, Но последний пример не будет работать в простом sh из-за конструкции (i = 0 ; i <= 100 ; i+=20). Поэтому для простого sh подойдёт следующий код:
#!/bin/sh { for i in $(seq 0 20 100); do sleep 1 echo $i done } | whiptail --gauge "Please wait while installing" 6 60 0
Связанные статьи:
- Как в Bash прочитать ввод пользователя в переменную? (75.8%)
- Как в Bash реализовать «Нажмите любую кнопку для продолжения» (51.6%)
- Как в Bash проверить, содержит ли строка подстроку (51.6%)
- Что такое башизм (bashisms) (51.6%)
- Функции в Bash: объявление, вызов и передача аргументов в функцию (51.6%)
- Лучшие терминальные мультиплексные инструменты (RANDOM - 1.6%)
А как комманду в чеклисте сделать ??
Я не понял, что именно вы спрашиваете.
Допустим, имеется ввиду, как выполнить команду на основе данных полученных из чеклиста.
В рассматриваемом примере информация из чек-листа сохраняется в переменную $DISTROS. Там может быть несколько значений, разделённых пробелами. Отсюда возникает новый вопрос — как разбить строку на введённые значения и выполнить определённые команды или проверки на основе полученных данных?
Для разбивки строки на слова (когда из одной строки создаются новые, разделённые по пробелам), используйте код:
Пример с чекбоксом:
Скриншоты:
Спасибо, буду учиться писать скрипты
Какие клавишы использовать при выборе чек листа? Со стороны пользователя. Я запустил скрипт, переломной чек-лист, но выбрать не одну позицию не могу. Какая клавиша отвечает за выбор?
Tab — для переключения между группами
←↑→↓ (курсорные клавиши) — для перехода по элементам
Space (пробел) для выбора или снятия выбора
Enter — для принятия изменений и закрытия окна (соответствует нажатию OK)
Вопрос по созданию блока для ввода пароля, можно ли использовать переменную с паролем в дальнейшем для других команд скрипта? Скажем подставлять его там, где требуется вводить sudo?
В каком смысле «можно»? В смысле «будет ли работать» - будет, почему бы и нет. В смысле «по соображениям безопасности» - зависит от конкретной реализации и условий использования.
Если можно, то как это сделать? Я пытался так, но это не работает.
#!/bin/bash
PASSWORD=$(whiptail --title
"Теста блока пароля"
--passwordbox
"Введите ваш пароль и нажмите ОК для продолжения."
10 60 3>&1 1>&2 2>&3)
exitstatus=$?
if
[ $exitstatus = 0 ];
then
echo $PASSWORD | sudo dnf -команда
else
echo
"Вы выбрали отмену."
fi
Приветствую! Посмотрите на следующий код:
В нём в echo "$PASSWORD" имя переменной взято в кавычки. Также добавлена опция -S (означает считывать пароль из стандартного ввода вместо приглашения командной строки) к sudo. В качестве команды использована whoami.
Спасибо, всё работает, но почему-то запоминает пароль всего на 5 минут, если скрипт большой, то в какой-то момент в терминале появляется просьба ввести пароль заново. Как сделать, чтобы он помнил пароль до выхода из текущей сессии?
Поскольку пароль уже сохранён в переменной, то в теории ничего не мешает вместо запуска команд следующим синтаксисом
Запускать их следующим образом каждый раз, даже когда это, может быть, и не требуется:
То есть если таймаут хеширования учётных данных уже истёк (требуется ввод пароля заново), то конструкция отработает как надо. Если таймаут хеширования пароля не истёк, то хотя ввод пароля и не требуется, команда должна запуститься без каких-либо ошибок и лишних сообщений.