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 

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

Linux

Как автоматизировать вход по SSH с паролем?

Linux

Как узнать максимальное количество потоков на процесс в Linux?

Linux

Недостатки и уязвимости использования LVM

Linux

Стоит ли блокировать ICMP?