zaLinux.ru

Как создавать диалоговые блоки в интерактивных shell скриптах


Когда вы устанавливаете новые программы в терминале, вы могли часто видеть появляющиеся информативные диалоговые блоки для обратной связи с вами. Типы диалоговых блоков различны: от простых диалогов да/нет до полей ввода, блоков паролей, чеклистов, меню и так далее. Преимущества использования таких дружественных к пользователю блоков очевидны, ведь они интуитивно направляют вас для ввода необходимой информации.

Когда вы пишите интерактивный шелл скрипт, вы на самом деле можете использовать такие диалоговые блоки для принятия ввода пользователя. Будучи предварительно установленной на всех современных дистрибутивах Linux, программа под названием whiptail может упростить процесс создания шелл скриптом диалоговых и информационных блоков в терминале наподобие тех, что графических интерфейсов, что кодируют Zenity или Xdialog для скриптов.

В этом уроке я опишу как с использованием whiptail создать дружественный пользователю диалоговые блоки в шел скрипте. Я также покажу Баш фрагменты кода различных диалоговых блоков, поддерживаемых в whiptail.

Создаём блок с сообщением

Блок с сообщением показывает произвольный текст с кнопкой подтверждения для продолжения.

whiptail --title "<название бокса>" --msgbox "<текст для показа>" <высота> <ширина>

Пример:

#!/bin/bash
whiptail --title "Бокс с сообщением" --msgbox "Создаём информационный блок с whiptail. Нажмите Ok для продолжения." 10 60

01

Создание Да/Нет блоков

Одним из частных пользовательских вводов является Да или Нет. В этом случае может быть использован диалоговый блок Да/Нет.

whiptail --title "<название диалогового блока>" --yesno "<текст для показа>" <высота> <ширина>

Пример:

#!/bin/bash
if (whiptail --title "Пробуем блок Да/Нет" --yesno "Выберите между Да или Нет." 10 60) then
echo "Вы выбрали Да. Статус выхода был $?."
else
echo "Вы выбрали нет. Статус выхода был $?."
fi

02

Опционально вы можете настроить текст кнопок Да и Нет с помощью опций "--yes-button" and "--no-button"

Например:

#!/bin/bash
if (whiptail --title "Тестируем блок Да/Нет" --yes-button "Кола" --no-button "Пепси" --yesno "Что вам нравится больше?" 10 60) then
echo "Вы выбрали Колу. Статус выхода был $?."
else
echo "Вы выбрали Пепси. Статус выхода был $?."
fi

03

Создаём блок свободного ввода

Если вы хотите принять любой произвольный текст от пользователя, вы можете использовать этот блок ввода

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

04

Создание блока для ввода пароля

Блок пароля полезен, когда вы хотите получить чувствительную информацию от пользователя.

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

05


Создание меню

Когда вы хотите спросить пользователя выбрать один из нескольких произвольных вариантов, вы можете использовать меню.

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

06

Создание диалога радиолист

Блок радиолист схож по смыслу с меню в том смысле, что вы можете выбрать только одну опцию из списка доступных опций. В отличие от блока меню, тем не менее, вы можете отобразить, какая опция выбрана по умолчанию, определив её статус.

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&gt;&amp;1 1&gt;&amp;2 2&gt;&amp;3)
exitstatus=$?
if [ $exitstatus = 0 ]; then
echo "Выбранный дистрибутив:"$DISTROS
else
echo "Вы нажали отмену."
fi

07

Создаём диалок чеклиста

Чеклист полезен, когда вы хотите попросить пользователя выбрать более чем один вариант из списка опций, он отличается от радиолиста, в котором можно сделать только один выбор.

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

08

Сооздание строки прогресса

Другой дружественный пользователю диалоговый блок это прогресс бар. 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

09


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

Рекомендуемые статьи:

11 Комментарии

  1. SGGT

    А как комманду в чеклисте сделать ??

     

    1. Alexey (Автор записи)

      Я не понял, что именно вы спрашиваете.

      Допустим, имеется ввиду, как выполнить команду на основе данных полученных из чеклиста.

      В рассматриваемом примере информация из чек-листа сохраняется в переменную $DISTROS. Там может быть несколько значений, разделённых пробелами. Отсюда возникает новый вопрос — как разбить строку на введённые значения и выполнить определённые команды или проверки на основе полученных данных?

      Для разбивки строки на слова (когда из одной строки создаются новые, разделённые по пробелам), используйте код:

      for word in $DISTROS
      do
      	КОМАНДЫ
      done

      Пример с чекбоксом:

      #!/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
      
      echo
      
      echo "Разберём введёную строку на слова:"
      for word in $DISTROS
      do
      	echo $word
      done
      
      echo
      
      echo "Выполним проверки исходя из введённых строк:"
      for word in $DISTROS
      do
      	if [ $word == "\"debian\"" ]; then
      		echo "Вы выбрали Debian"
      	fi
      	if [ $word == "\"ubuntu\"" ]; then
      		echo "Вы выбрали Ubuntu"
      	fi
      	if [ $word == "\"centos\"" ]; then
      		echo "Вы выбрали CentOS"
      	fi
      	if [ $word == "\"mint\"" ]; then
      		echo "Вы выбрали Linux Mint"
      	fi
      done

      Скриншоты:

      1. SGGT

        Спасибо, буду учиться писать скрипты

  2. Виктор

    Какие клавишы использовать при выборе чек листа? Со стороны пользователя. Я запустил скрипт, переломной чек-лист, но выбрать не одну позицию не могу. Какая клавиша отвечает за выбор?

    1. Alexey (Автор записи)

      Tab — для переключения между группами

      ←↑→↓ (курсорные клавиши) — для перехода по элементам

      Space (пробел) для выбора или снятия выбора

      Enter — для принятия изменений и закрытия окна (соответствует нажатию OK)

  3. Александр

    Вопрос по созданию блока для ввода пароля, можно ли использовать переменную с паролем в дальнейшем для других команд скрипта? Скажем подставлять его там, где требуется вводить sudo?

    1. Alexey (Автор записи)

      В каком смысле «можно»? В смысле «будет ли работать» - будет, почему бы и нет. В смысле «по соображениям безопасности» - зависит от конкретной реализации и условий использования.

      1. Александр

        Если можно, то как это сделать? Я пытался так, но это не работает.

        #!/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

        1. Alexey (Автор записи)

          Приветствую! Посмотрите на следующий код:

          PASSWORD=$(whiptail --title "Теста блока пароля" --passwordbox "Введите ваш пароль и нажмите ОК для продолжения." 10 60 3>&1 1>&2 2>&3)
          
          exitstatus=$?
          
          if [ $exitstatus = 0 ]; then
          
          	echo "$PASSWORD" | sudo -S whoami
          
          else
          
          echo "Вы выбрали отмену."
          
          fi

          В нём в echo "$PASSWORD" имя переменной взято в кавычки. Также добавлена опция -S (означает считывать пароль из стандартного ввода вместо приглашения командной строки) к sudo. В качестве команды использована whoami.

          1. Александр22.10.2022 в 10:45 Если можно, то как э

            Спасибо, всё работает, но почему-то запоминает пароль всего на 5 минут, если скрипт большой, то в какой-то момент в терминале появляется просьба ввести пароль заново. Как сделать, чтобы он помнил пароль до выхода из текущей сессии?

            1. Alexey (Автор записи)

              Поскольку пароль уже сохранён в переменной, то в теории ничего не мешает вместо запуска команд следующим синтаксисом

              sudo КОМАНДА

              Запускать их следующим образом каждый раз, даже когда это, может быть, и не требуется:

              echo "$PASSWORD" | sudo -S КОМАНДА

              То есть если таймаут хеширования учётных данных уже истёк (требуется ввод пароля заново), то конструкция отработает как надо. Если таймаут хеширования пароля не истёк, то хотя ввод пароля и не требуется, команда должна запуститься без каких-либо ошибок и лишних сообщений.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *