linux - मैं लिनक्स खोल स्क्रिप्ट में हां/नहीं/रद्द इनपुट के लिए कैसे संकेत करूं?




bash shell (17)

मैं एक शेल स्क्रिप्ट में इनपुट रोकना चाहता हूं, और उपयोगकर्ता को विकल्पों के लिए संकेत देता हूं। मानक 'हां, नहीं, या रद्द करें' प्रकार का प्रश्न। मैं इसे एक विशिष्ट बाश प्रॉम्प्ट में कैसे पूरा करूं?


एक सामान्य प्रश्न के लिए कम से कम पांच जवाब।

इस पर निर्भर करते हुए

  • posix अनुपालन: जेनेरिक shell वातावरण के साथ खराब सिस्टम पर काम कर सकता है
  • bash विशिष्ट: तथाकथित bashisms का उपयोग कर

और यदि आप चाहते हैं

  • सरल '`लाइन में' प्रश्न / उत्तर (जेनेरिक समाधान)
  • सुंदर प्रारूपित इंटरफेस, जैसे ncurses या libgtk या libqt का उपयोग कर अधिक ग्राफिकल ...
  • शक्तिशाली रीडलाइन इतिहास क्षमता का उपयोग करें

1. POSIX जेनेरिक समाधान

आप read कमांड का उपयोग कर सकते हैं, उसके बाद if ... then ... else :

echo -n "Is this a good question (y/n)? "
read answer

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

# ( एडम काट्ज़ की टिप्पणी के लिए धन्यवाद: यह परीक्षण अधिक पोर्टेबल है और एक कांटा से बचें :)

if [ "$answer" != "${answer#[Yy]}" ] ;then
    echo Yes
else
    echo No
fi

POSIX, लेकिन एकल कुंजी सुविधा

लेकिन अगर आप नहीं चाहते कि उपयोगकर्ता को रिटर्न हिट करना पड़े, तो आप लिख सकते हैं:

( संपादित: जैसा कि @ जोनाथन लेफ्लर सही तरीके से सुझाव देते हैं, स्टटी की कॉन्फ़िगरेशन को सहेजने से उन्हें बेहतर बनाने के लिए मजबूर होना बेहतर हो सकता है।)

echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
    echo Yes
else
    echo No
fi

नोट: यह sh , bash , ksh , dash और busybox अंतर्गत परीक्षण किया गया था!

वही, लेकिन वाई या एन के लिए स्पष्ट रूप से इंतजार कर रहा है:

#/bin/sh
echo -n "Is this a good question (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

समर्पित उपकरणों का उपयोग करना

libncurses , libgtk , libqt या अन्य ग्राफिकल पुस्तकालयों का उपयोग करके बनाए गए कई टूल हैं। उदाहरण के लिए, whiptail का उपयोग कर:

if whiptail --yesno "Is this a good question" 20 60 ;then
    echo Yes
else
    echo No
fi

आपके सिस्टम के आधार पर, आपको एक और समान उपकरण के साथ whiptail को प्रतिस्थापित करने की आवश्यकता हो सकती है:

dialog --yesno "Is this a good question" 20 60 && echo Yes

gdialog --yesno "Is this a good question" 20 60 && echo Yes

kdialog --yesno "Is this a good question" 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 ...

2. बैश विशिष्ट समाधान

लाइन विधि में मूल

read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
    y|Y )
        echo Yes
    ;;
    * )
        echo No
    ;;
esac

मैं case का उपयोग करना पसंद करता हूं इसलिए मैं yes | ja | si | oui लिए भी परीक्षण कर सकता हूं yes | ja | si | oui अगर जरूरत पड़ती है ...

एकल कुंजी सुविधा के साथ लाइन में

बैश के तहत, हम read आदेश के लिए इच्छित इनपुट की लंबाई निर्दिष्ट कर सकते हैं:

read -n 1 -p "Is this a good question (y/n)? " answer

बैश के तहत, कमांड कमांड एक टाइमआउट पैरामीटर स्वीकार करता है, जो उपयोगी हो सकता है।

read -t 3 -n 1 -p "Is this a good question (y/n)? " answer
[ -z "$answer" ] && answer="Yes"  # if 'yes' have to be default choice

समर्पित उपकरणों के लिए कुछ चालें

सरल yes - no से परे अधिक परिष्कृत संवाद बॉक्स yes - no उद्देश्य yes - no :

dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe

प्रगति पट्टी:

dialog --gauge "Filling the tank" 20 60 0 < <(
    for i in {1..100};do
        printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
        sleep .033
    done
) 

लिटिल डेमो:

#!/bin/sh
while true ;do
    [ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
    DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&1 \
            whiptail       "dialog boxes from shell scripts" >/dev/tty \
            dialog         "dialog boxes from shell with ncurses" \
            gdialog        "dialog boxes from shell with Gtk" \
            kdialog        "dialog boxes from shell with Kde" ) || exit
    clear;echo "Choosed: $DIALOG."
    for i in `seq 1 100`;do
        date +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"
        sleep .0125
      done | $DIALOG --gauge "Filling the tank" 20 60 0
    $DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
    sleep 3
    if $DIALOG --yesno  "Do you like this demo?" 20 60 ;then
        AnsYesNo=Yes; else AnsYesNo=No; fi
    AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
    AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
    $DIALOG --textbox /etc/motd 20 60
    AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
        Correct "This demo is useful"        off \
        Fun        "This demo is nice"        off \
        Strong        "This demo is complex"        on 2>&1 >/dev/tty)
    AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \
        " -1" "Downgrade this answer"        off \
        "  0" "Not do anything"                on \
        " +1" "Upgrade this anser"        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. रीडलाइन के इतिहास का उपयोग करना

उदाहरण:

#!/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 "Doing something with '$line'" ;;
      esac
  done

इससे आपकी $HOME निर्देशिका में एक फ़ाइल। .myscript.history जाएगी, आप रीडलाइन के इतिहास कमांड का उपयोग कर सकते हैं, जैसे ऊपर , नीचे , Ctrl + r और अन्य।


हां / नहीं / रद्द करें

समारोह

#!/usr/bin/env bash
@confirm() {
  local message="$*"
  local result=''

  echo -n "> $message (Yes/No/Cancel) " >&2

  while [ -z "$result" ] ; do
    read -s -n 1 choice
    case "$choice" in
      y|Y ) result='Y' ;;
      n|N ) result='N' ;;
      c|C ) result='C' ;;
    esac
  done

  echo $result
}

प्रयोग

case $(@confirm 'Confirm?') in
  Y ) echo "Yes" ;;
  N ) echo "No" ;;
  C ) echo "Cancel" ;;
esac

स्वच्छ उपयोगकर्ता इनपुट के साथ पुष्टि करें

समारोह

#!/usr/bin/env bash
@confirm() {
  local message="$*"
  local result=3

  echo -n "> $message (y/n) " >&2

  while [[ $result -gt 1 ]] ; do
    read -s -n 1 choice
    case "$choice" in
      y|Y ) result=0 ;;
      n|N ) result=1 ;;
    esac
  done

  return $result
}

प्रयोग

if @confirm 'Confirm?' ; then
  echo "Yes"
else
  echo "No"
fi

@ मार्क और @ मिरडिन के उत्तरों से प्रेरित मैंने इस समारोह को सार्वभौमिक संकेत के लिए बनाया है

uniprompt(){
    while true; do
        echo -e "$1\c"
        read opt
        array=($2)
        case "${array[@]}" in  *"$opt"*) eval "$3=$opt";return 0;; esac
        echo -e "$opt is not a correct value\n"
    done
}

इस तरह इसका इस्तेमाल करें:

unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"

अधिक सामान्य होगा:

function menu(){
    title="Question time"
    prompt="Select:"
    options=("Yes" "No" "Maybe")
    echo "$title"
    PS3="$prompt"
    select opt in "${options[@]}" "Quit/Cancel"; do
        case "$REPLY" in
            1 ) echo "You picked $opt which is option $REPLY";;
            2 ) echo "You picked $opt which is option $REPLY";;
            3 ) echo "You picked $opt which is option $REPLY";;
            $(( ${#options[@]}+1 )) ) clear; echo "Goodbye!"; exit;;
            *) echo "Invalid option. Try another one.";continue;;
         esac
     done
     return
}

एक अच्छा ncurses- जैसे इनपुटबॉक्स प्राप्त करने के लिए इस तरह कमांड संवाद का उपयोग करें:

#!/bin/bash
if (dialog --title "Message" --yesno "Want to do something risky?" 6 25)
# message box will have the size 25x6 characters
then 
    echo "Let's do something risky"
    # do something risky
else 
    echo "Let's stay boring"
fi

डायलॉग पैकेज कम से कम एसयूएसई लिनक्स के साथ डिफ़ॉल्ट रूप से स्थापित किया जाता है।


एक लाइन कमांड के दोस्त के रूप में मैंने निम्नलिखित का उपयोग किया:

while [ -z $prompt ]; do read -p "Continue (y/n)?" choice;case "$choice" in y|Y ) prompt=true; break;; n|N ) exit 0;; esac; done; prompt=;

लिखित लम्बाई, यह इस तरह काम करता है:

while [ -z $prompt ];
  do read -p "Continue (y/n)?" choice;
  case "$choice" in
    y|Y ) prompt=true; break;;
    n|N ) exit 0;;
  esac;
done;
prompt=;

ऐसा करने का एक आसान तरीका xargs -p या gnu parallel --interactive

मुझे xargs के व्यवहार को थोड़ा बेहतर पसंद है क्योंकि यह अंत में चलाने के लिए yesses को इकट्ठा करने के बजाय, अन्य इंटरैक्टिव यूनिक्स कमांड जैसे प्रॉम्प्ट के तुरंत बाद प्रत्येक कमांड निष्पादित करता है। (आप जो चाहते थे उसके माध्यम से प्राप्त करने के बाद आप Ctrl-C कर सकते हैं।)

जैसे,

echo *.xml | xargs -p -n 1 -J {} mv {} backup/

ऐसी पुरानी पोस्ट पर पोस्ट करने के लिए खेद है। कुछ हफ्ते पहले मुझे एक ही समस्या का सामना करना पड़ रहा था, मेरे मामले में मुझे एक समाधान की आवश्यकता थी जो ऑनलाइन इंस्टॉलर-स्क्रिप्ट के भीतर भी काम करता था, उदाहरण के लिए: curl -Ss https://raw.github.com/_____/installer.sh | bash curl -Ss https://raw.github.com/_____/installer.sh | bash

read yesno < /dev/tty का उपयोग करना मेरे लिए ठीक है:

echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno < /dev/tty

if [ "x$yesno" = "xy" ];then

   # Yes
else

   # No
fi

उम्मीद है कि यह किसी की मदद करता है।


बैश ने इस उद्देश्य के लिए select किया है।

select result in Yes No Cancel
do
    echo $result
done

मेरा सुझाव है कि आप संवाद का उपयोग करें ...

लिनक्स अपरेंटिस: संवाद का उपयोग करके बैश शैल स्क्रिप्ट को बेहतर बनाएं

संवाद कमांड अपने उपयोग को अधिक इंटरैक्टिव बनाने के लिए शेल स्क्रिप्ट में विंडो बक्से के उपयोग को सक्षम बनाता है।

यह सरल और उपयोग करने में आसान है, यहां एक जीनोम संस्करण भी है जिसे gdialog कहा जाता है जो सटीक समान पैरामीटर लेता है, लेकिन यह एक्स पर जीयूआई शैली दिखाता है।


मैंने देखा कि इस तरह के साधारण उपयोगकर्ता इनपुट के लिए बहु-पंक्ति इको मेनू दिखाने का कोई जवाब नहीं पोस्ट किया गया है, इसलिए यहां मेरा जाना है:

#!/bin/bash

function ask_user() {    

echo -e "
#~~~~~~~~~~~~#
| 1.) Yes    |
| 2.) No     |
| 3.) Quit   |
#~~~~~~~~~~~~#\n"

read -e -p "Select 1: " choice

if [ "$choice" == "1" ]; then

    do_something

elif [ "$choice" == "2" ]; then

    do_something_else

elif [ "$choice" == "3" ]; then

    clear && exit 0

else

    echo "Please select 1, 2, or 3." && sleep 3
    clear && ask_user

fi
}

ask_user

इस विधि को उम्मीद में पोस्ट किया गया था कि किसी को इसे उपयोगी और समय-बचत मिल सकती है।


यह समाधान एक एकल चरित्र को पढ़ता है और हां प्रतिक्रिया पर एक फ़ंक्शन को कॉल करता है।

read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    do_something      
fi

read कमांड का प्रयोग करें:

echo Would you like to install? "(Y or N)"

read x

# now check if $x is "y"
if [ "$x" = "y" ]; then
    # do something here!
fi

और फिर आपको आवश्यक सभी अन्य सामान


शेल प्रॉम्प्ट पर उपयोगकर्ता इनपुट प्राप्त करने के लिए सबसे सरल और सबसे व्यापक रूप से उपलब्ध विधि read कमांड है। इसके उपयोग को चित्रित करने का सबसे अच्छा तरीका एक साधारण प्रदर्शन है:

while true; do
    read -p "Do you wish to install this program?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done

स्टीवन हूविग द्वारा इंगित एक अन्य विधि, बैश का select कमांड है। select का उपयोग कर एक ही उदाहरण यहां दिया गया है:

echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
    case $yn in
        Yes ) make install; break;;
        No ) exit;;
    esac
done

select साथ आपको इनपुट को स्वच्छ करने की आवश्यकता नहीं है - यह उपलब्ध विकल्पों को प्रदर्शित करता है, और आप अपनी पसंद के अनुरूप एक संख्या टाइप करते हैं। यह स्वचालित रूप से लूप भी होता है, इसलिए अगर वे अमान्य इनपुट देते हैं तो पुनः प्रयास करने के लिए कुछ while true लूप की आवश्यकता नहीं होती है।

इसके अलावा, कृपया एफ। हॉरी द्वारा उत्कृष्ट उत्तर देखें ।


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 'Invalid response -- please reenter:';
           read answer;;
       esac
    fi
  done
}

... other stuff

inquire "Install now?"

...

read -e -p "Enter your choice: " choice

-e विकल्प उपयोगकर्ता को तीर कुंजियों का उपयोग करके इनपुट संपादित करने में सक्षम बनाता है।

यदि आप इनपुट के रूप में सुझाव का उपयोग करना चाहते हैं:

read -e -i "yes" -p "Enter your choice: " choice

-i विकल्प एक सूचक इनपुट मुद्रित करता है।


yn() {
  if [[ 'y' == `read -s -n 1 -p "[y/n]: " Y; echo $Y` ]];
  then eval $1;
  else eval $2;
  fi }
yn 'echo yes' 'echo no'
yn 'echo absent no function works too!'




scripting