Linux

Как мне запросить ввод Да/Нет/Отмена в сценарии оболочки Linux

Я хочу приостановить ввод в сценарии оболочки и предложить пользователю выбор.
Стандартный вопрос YesNo или Cancel.
Как мне сделать это в обычном приглашении bash?

 

Ответ 1

Самым простым и широко доступным методом получения пользовательского ввода в интерпретаторе shell является команда read. Лучший способ проиллюстрировать ее использование это простая демонстрация:

while true; do

    read -p "Хотите ли вы установить эту программу?" yn

    case $yn in

        [Yy]* ) make install; break;;

        [Nn]* ) exit;;

        * ) echo "Пожалуйста, ответьте да или нет.";;

    esac

done

 

Другой метод — это команда select в Bash. Вот тот же пример с использованием команды select:

echo " Хотите ли вы установить эту программу?"

select yn in "Да" "Нет"; do

    case $yn in

        Yes ) make install; break;;

        No ) exit;;

    esac

done

 

При использовании select вам не нужно корректировать вводимые данные — она отображает доступные варианты, а вы вводите число, соответствующее вашему выбору. Она также автоматически зацикливается, поэтому нет необходимости в цикле while true для повторных попыток в случае ввода неверных данных.

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

set -- $(locale LC_MESSAGES)

yesptrn="$1"; noptrn="$2"; yesword="$3"; noword="$4"

while true; do

    read -p "Install (${yesword} / ${noword})? " yn

    if [[ "$yn" =~ $yesexpr ]]; then make install; exit; fi

    if [[ "$yn" =~ $noexpr ]]; then exit; fi

    echo "Answer ${yesword} / ${noword}."

done

 

Ответ 2

Есть, по крайней мере, пять вариантов ответов на этот вопрос.

Варианты:

  • Posix совместимый: может работать на старых системах с универсальной оболочкой

  • Использовать так называемые башизмы

  • Простые встроенные вопросы/ответы (типовые решения)

  • Красивые форматированные интерфейсы, например, ncurses или графические, используя libgtk или libqt ...

  • Использовать мощные возможности истории readline

 

1. Общие решения POSIX

Вы можете использовать команду read, за которой следует if ... then ... else:

echo -n "Хороший ли это вопрос (y/n)? "

read answer

if [ "$answer" != "${answer#[Yy]}" ] ;then

    echo Yes

else

    echo No

fi

 

2. POSIX, но с некоторой ключевой особенностью

Но если вы не хотите, чтобы пользователь нажимал клавишу Enter, вы можете написать:

echo -n " Хороший ли это вопрос (y/n)? "

old_stty_cfg=$(stty -g)

stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # осторожно с stty

if echo "$answer" | grep -iq "^y" ;then

    echo Yes

else

    echo No

fi

 

То же самое, но с явным ожиданием Y/N:

#/bin/sh

echo -n " Хороший ли это вопрос (y/n)? "

old_stty_cfg=$(stty -g)

stty raw -echo

answer=$( while ! head -c 1 | grep -i '[ny]' ;do true ;done )

stty $old_stty_cfg

if echo "$answer" | grep -iq "^y" ;then

    echo Yes

else

    echo No

fi

 

Использование специальных инструментов

Есть много инструментов , которые были собраны с использованием libncurseslibgtklibqt или с другими графическими библиотеками. Например, используя whiptail:

if whiptail --yesno " Хороший ли это вопрос " 20 60 ;then

    echo Yes

else

    echo No

fi

 

В зависимости от вашей системы вам может потребоваться заменить whiptail на другой аналогичный инструмент:

dialog --yesno " Хороший ли это вопрос " 20 60 && echo Yes

gdialog --yesno " Хороший ли это вопрос " 20 60 && echo Yes

kdialog --yesno " Хороший ли это вопрос " 20 60 && echo Yes

где 20высота диалогового окна в строках, а 60ширина диалогового окна. Все эти инструменты имеют примерно одинаковый синтаксис.

DIALOG=whiptail

if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi

if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi

...

$DIALOG --yesno ...

 

3. Решения, специфичные для Bash

Базовый метод:

read -p " Хороший ли это вопрос (y/n)? " answer

case ${answer:0:1} in

    y|Y )

        echo Yes

    ;;

    * )

        echo No

    ;;

esac

Я предпочитаю использовать case,чтобы yes | ja | si | oui при необходимости можно было протестировать ...

В bash мы можем указать длину предполагаемого ввода для команды read:

read -n 1 -p " Хороший ли это вопрос (y/n)? " answer

В bash команда read принимает параметр тайм-аута, который может быть полезен.

read -t 3 -n 1 -p " Хороший ли это вопрос (y/n)? " answer

[ -z "$answer" ] && answer="Yes"  # да, это выбор по умолчанию

 

4. Некоторые хитрости для специальных инструментов

Более сложные диалоговые окна, выходящие за рамки yes – no выбора:

dialog --menu "Хороший ли это вопрос" 20 60 12 y Yes n No m Maybe

Индикатор:

dialog --gauge "Заполнение индикатора" 20 60 0 < <(

    for i in {1..100};do

        printf "XXX\n%d\n%(%a %b %T)T индикатор: %d\nXXX\n" $i -1 $i

        sleep .033

    done

 

Маленькая демонстрация:

#!/bin/sh

while true ;do

    [ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog

    DIALOG=$($DIALOG --menu "Выберите инструмент для запуска" 20 60 12 2>&1 \

            whiptail       "диалог для оболочки скрипта >/dev/tty \

            dialog         "диалог для оболочки ncurses" \

            gdialog        "диалог для оболочки Gtk" \

            kdialog        "диалог для оболочки Kde" ) || exit

    clear;echo "Выбрано: $DIALOG."

    for i in `seq 1 100`;do

        date +"`printf "XXX\n%d\n%%a %%b %%T индикатор: %d\nXXX\n" $i $i`"

        sleep .0125

      done | $DIALOG --gauge "Заполнение индикатора" 20 60 0

    $DIALOG --infobox "Это простое информационное сообщение\n\n\nНе требуется никаких действий " 20 60

    sleep 3

    if $DIALOG --yesno  "Нравится ли вам эта демонстрация?" 20 60 ;then

        AnsYesNo=Yes; else AnsYesNo=No; fi

    AnsInput=$($DIALOG --inputbox "Текст:" 20 60 "Текст здесь..." 2>&1 >/dev/tty)

    AnsPass=$($DIALOG --passwordbox "Пароль:" 20 60 "..." 2>&1 >/dev/tty)

    $DIALOG --textbox /etc/motd 20 60

    AnsCkLst=$($DIALOG --checklist "Проверка..." 20 60 12 \

        Correct      "Успех"        off \

        Fun            "Нормально"        off \

        Strong        "В комплексе"        on 2>&1 >/dev/tty)

    AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \

        " -1" "Понизить рейтинг этого ответа "        off \

        "  0" "Ничего не делать "                on \

        " +1" "Обновить этот ответ "        off 2>&1 >/dev/tty)

    out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"

    $DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio" 20 60

  done

 

5. Использование истории readline

Пример:

#!/bin/bash

set -i

HISTFILE=~/.myscript.history

history -c

history -r

 

myread() {

    read -e -p '> ' $1

    history -s ${!1}

}

trap 'history -a;exit' 0 1 2 3 6

while myread line;do

    case ${line%% *} in

        exit )  break ;;

        *    )  echo "Сделать что-то с '$line'" ;;

      esac

  done

Это создаст файл .myscript.history в вашем каталоге $HOME, после чего вы сможете использовать команды истории readline, такие как Up, Down, Ctrl+r и другие.

 

Ответ 3

Вы можете использовать встроенную команду read. Используйте опцию -p, чтобы задать пользователю вопрос. Начиная с BASH4, вы можете использовать опцию -i, чтобы предложить ответ:

read -e -p "Введите путь к файлу: " -i "/usr/local/etc/" FILEPATH

echo $FILEPATH

(Но не забудьте использовать опцию «readline», -e,чтобы разрешить редактирование строки с помощью клавиш со стрелками).

Если вам нужна логика «да/нет», вы можете сделать что-то вроде этого:

read -e -p "

Перечислите содержимое вашей корневой папки [Y/n] " YN

[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/

 

Ответ 4

inquire ()  {

  echo  -n "$1 [y/n]? "

  read answer

  finish="-1"

  while [ "$finish" = '-1' ]

  do

    finish="1"

    if [ "$answer" = '' ];

    then

      answer=""

    else

      case $answer in

        y | Y | yes | YES ) answer="y";;

        n | N | no | NO ) answer="n";;

        *) finish="-1";

           echo -n 'Неверный ответ – попробуйте снова:';

           read answer;;

       esac

    fi

  done

}

 

...

 

inquire "Установить сейчас?"

...

 

Ответ 5

В оболочке POSIX можно обрабатывать «выбор Да/Нет» с учетом локали; используя записи категории LC_MESSAGES локали, witch предоставляет готовые шаблоны RegEx для соответствия входу строки для локализованных Да/Нет.

#!/usr/bin/env sh

# Получение значений LC_MESSAGES в переменные

# shellcheck disable=SC2046 # Намеренное разделение IFS

IFS='

' set -- $(locale LC_MESSAGES)

yesexpr="$1"

noexpr="$2"

yesstr="$3"

nostr="$4"

messages_codeset="$5" # здесь не используется, но сохраняется как документация

# Отображение запроса "Да/Нет?" в локали

echo "$yesstr / $nostr ?"

# Чтение ответа

read -r yn

# Тестирование ответа

case "$yn" in

# работать только с классом символов из выражения

  ${yesexpr##^}) echo "ответ $yesstr" ;;

  ${noexpr##^}) echo "ответ $nostr" ;;

esac 

Схожие статьи

Что такое сетевой сканер Ubuntu, как его правильно настроить
Linux

Что такое сетевой сканер Ubuntu, как его правильно настроить

Linux

Почему происходит высокая загрузка ЦП при низкой средней нагрузке?

Как произвести DeadBeef настройку: руководство для пользователей
Linux

Как произвести DeadBeef настройку: руководство для пользователей

Linux

Стоит ли использовать автоматическое развертывание Linux и управление конфигурацией в небольших масштабах?

×