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!'