ฉันต้องการหยุดการป้อนข้อมูลในเชลล์สคริปต์และแจ้งให้ผู้ใช้เลือกได้
มาตรฐานYes
, No
หรือCancel
คำถามประเภท
ฉันจะทำสิ่งนี้ให้สำเร็จได้ในพรอมต์ทุบตีทั่วไป
ฉันต้องการหยุดการป้อนข้อมูลในเชลล์สคริปต์และแจ้งให้ผู้ใช้เลือกได้
มาตรฐานYes
, No
หรือCancel
คำถามประเภท
ฉันจะทำสิ่งนี้ให้สำเร็จได้ในพรอมต์ทุบตีทั่วไป
คำตอบ:
วิธีที่ง่ายที่สุดและแพร่หลายที่สุดในการรับอินพุตของผู้ใช้ที่เชลล์พรอมต์คือ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
อีกวิธีหนึ่ง, ชี้ให้เห็นโดยSteven Huwigเป็นทุบตีของ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
ซ้ำโดยอัตโนมัติจึงไม่จำเป็นต้องวนซ้ำเพื่อลองอีกครั้งหากมีการป้อนข้อมูลที่ไม่ถูกต้อง
นอกจากนี้Léa Grisแสดงให้เห็นถึงวิธีการที่จะทำให้ไม่เชื่อเรื่องพระเจ้าภาษาคำขอในคำตอบของเธอ การปรับตัวอย่างแรกของฉันเพื่อให้บริการหลายภาษาได้ดีขึ้นอาจมีลักษณะเช่นนี้:
set -- $(locale LC_MESSAGES)
yesptrn="$1"; noptrn="$2"; yesword="$3"; noword="$4"
while true; do
read -p "Install (${yesword} / ${noword})? " yn
case $yn in
${yesptrn##^} ) make install; break;;
${noptrn##^} ) exit;;
* ) echo "Answer ${yesword} / ${noword}.";;
esac
done
เห็นได้ชัดว่าสตริงการสื่อสารอื่น ๆ ยังคงไม่ได้แปลที่นี่ (ติดตั้งตอบ) ซึ่งจะต้องได้รับการแก้ไขในการแปลที่สมบูรณ์มากขึ้น แต่แม้การแปลบางส่วนจะเป็นประโยชน์ในหลาย ๆ กรณี
สุดท้ายโปรดตรวจสอบคำตอบที่ดีเยี่ยมโดยเอฟ HAURI
exit
เป็นbreak
ปิดไม่ให้แท็บเมื่อฉันเลือก 'ไม่'
break
ในselect
กรณีที่ไม่มีห่วง?
ขึ้นอยู่กับ
และถ้าคุณต้องการ
คุณสามารถใช้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
(ขอบคุณความคิดเห็นของ Adam Katz : แทนที่การทดสอบข้างต้นด้วยแบบพกพาที่มากขึ้นและหลีกเลี่ยงหนึ่งส้อม :)
แต่ถ้าคุณไม่ต้องการให้ผู้ใช้ตีReturnคุณสามารถเขียน:
( แก้ไข:ตามที่ @JonathanLeffler แนะนำอย่างถูกต้องการบันทึกการกำหนดค่าของ stty อาจดีกว่าเพียงแค่บังคับให้มีสติ )
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
หมายเหตุ:นี่คือการทดสอบภายใต้ดวลจุดโทษ, ทุบตี, ksh, ชน และ busybox!
เหมือนกัน แต่รออย่างชัดเจนสำหรับyหรือn:
#/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 ...
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
ถ้าจำเป็น ...
ภายใต้ bash เราสามารถระบุความยาวของอินพุตที่ต้องการสำหรับread
คำสั่ง:
read -n 1 -p "Is this a good question (y/n)? " answer
ภายใต้ bash read
คำสั่งยอมรับพารามิเตอร์การหมดเวลาซึ่งอาจเป็นประโยชน์
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
จุดประสงค์ง่ายๆ
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
ตัวอย่างเพิ่มเติม? ดูที่การใช้ whiptail สำหรับการเลือกอุปกรณ์USBและตัวเลือกที่เก็บข้อมูล USB ถอดได้: USBKeyChooser
ตัวอย่าง:
#!/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
นี้จะสร้างไฟล์.myscript.history
ของคุณใน$HOME
ไดเรกทอรีกว่าที่คุณสามารถใช้คำสั่งประวัติศาสตร์ ReadLine เหมือนUp, Down, Ctrl+ rและอื่น ๆ
stty
มีตัวเลือกสำหรับการใช้งาน:-g
นี้จะเรียกคืนการตั้งค่าตรงตามที่พวกเขาได้พบซึ่งอาจจะหรืออาจจะไม่เป็นเช่นเดียวกับold_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
stty -sane
case
สำหรับ POSIX เช่นเดียวกับทุบตี (ใช้สัญลักษณ์แทนสภาพมากกว่าย่อยทุบตี: case $answer in; [Yy]* ) echo Yes ;;
) แต่ฉันชอบใช้คำสั่งเงื่อนไขแทนความนิยมมากกว่าของคุณ[ "$answer" != "${answer#[Yy]}" ]
echo "$answer" | grep -iq ^y
มันพกพาได้มากกว่า (greps ที่ไม่ใช่ของ GNU บางตัวทำงานไม่-q
ถูกต้อง) และไม่มีการเรียกระบบ ${answer#[Yy]}
ใช้การขยายพารามิเตอร์เพื่อลบY
หรือออกy
จากจุดเริ่มต้น$answer
ทำให้เกิดความไม่เท่าเทียมกันเมื่อมีอยู่ ใช้งานได้ในเปลือก POSIX ใด ๆ (เส้นประ, ksh, bash, zsh, busybox ฯลฯ )
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
คุณสามารถใช้คำสั่งอ่านในตัว; ใช้-p
ตัวเลือกนี้เพื่อถามคำถามผู้ใช้
ตั้งแต่ BASH4 คุณสามารถใช้-i
เพื่อแนะนำคำตอบ:
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(แต่อย่าลืมใช้ตัวเลือก "readline" -e
เพื่ออนุญาตให้แก้ไขบรรทัดด้วยปุ่มลูกศร)
ถ้าคุณต้องการตรรกะ "ใช่ / ไม่ใช่" คุณสามารถทำสิ่งนี้:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
FILEPATH
เป็นชื่อตัวแปรที่คุณเลือกและตั้งค่าด้วยคำตอบของพรอมต์คำสั่ง ดังนั้นหากคุณต้องเปิดใช้vlc "$FILEPATH"
งานเช่นvlc
จะเปิดไฟล์นั้น
-e
ตัวอย่างที่สอง (ง่ายคือใช่ / ไม่ใช่)
-e -p
แทน-ep
?
-e
ตั้งค่าสถานะ / ตัวเลือกคุณอาจ (ขึ้นอยู่กับการนำไปใช้) ไม่สามารถพิมพ์ "y" แล้วเปลี่ยนความคิดของคุณและแทนที่ด้วย "n" (หรือสิ่งอื่นสำหรับเรื่องนั้น); เมื่อจัดทำเอกสารคำสั่งรายการตัวเลือกแยกต่างหากจะดีกว่าสำหรับการอ่าน / ความชัดเจนท่ามกลางเหตุผลอื่น ๆ
Bash ได้เลือกเพื่อจุดประสงค์นี้
select result in Yes No Cancel
do
echo $result
done
exit
ภายใน :)
Ctrl-D
แต่แน่นอนว่ารหัสจริงที่ใช้จะต้องหยุดพักหรือออกจากร่างกาย)
exit
จะออกจากสคริปต์ทั้งหมดเข้าด้วยกันbreak
จะออกจากลูปที่คุณอยู่เท่านั้น (ถ้าคุณอยู่บน a while
หรือcase
ลูป)
read -p "Are you alright? (y/n) " RESP
if [ "$RESP" = "y" ]; then
echo "Glad to hear it"
else
echo "You need more bash programming"
fi
นี่คือสิ่งที่ฉันรวบรวม:
#!/bin/sh
promptyn () {
while true; do
read -p "$1 " yn
case $yn in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer yes or no.";;
esac
done
}
if promptyn "is the sky blue?"; then
echo "yes"
else
echo "no"
fi
ฉันเป็นผู้เริ่มต้นดังนั้นเอาสิ่งนี้ด้วยเม็ดเกลือ แต่ดูเหมือนว่าจะใช้ได้
case $yn in
เป็นcase ${yn:-$2} in
คุณสามารถใช้อาร์กิวเมนต์ที่สองเป็นค่าเริ่มต้น Y หรือ N
case $yn
ในการcase "${yn:-Y}"
ที่จะมีใช่เป็นค่าเริ่มต้น
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?"
...
do_xxxx=y # In batch mode => Default is Yes
[[ -t 0 ]] && # If TTY => Prompt the question
read -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx # Store the answer in $do_xxxx
if [[ $do_xxxx =~ ^(y|Y|)$ ]] # Do if 'y' or 'Y' or empty
then
xxxx
fi
[[ -t 0 ]] && read ...
=> คำสั่งโทรread
ถ้า TTYread -n 1
=> รอหนึ่งตัวอักษร$'\e[1;32m ... \e[0m '
=> พิมพ์เป็นสีเขียว[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> bash regexdo_xxxx=y
[[ -t 0 ]] && { # Timeout 5 seconds (read -t 5)
read -t 5 -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx || # read 'fails' on timeout
do_xxxx=n ; } # Timeout => answer No
if [[ $do_xxxx =~ ^(y|Y|)$ ]]
then
xxxx
fi
วิธีที่ง่ายที่สุดในการบรรลุเป้าหมายด้วยจำนวนบรรทัดน้อยที่สุดมีดังนี้:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
นี่if
เป็นเพียงตัวอย่าง: มันขึ้นอยู่กับคุณว่าจะจัดการกับตัวแปรนี้อย่างไร
ใช้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 -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
echo
เพื่อดูด้วยตัวคุณเอง
ในการรับค่าอินพุตเหมือน 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
แพ็คเกจการโต้ตอบถูกติดตั้งโดยค่าเริ่มต้นอย่างน้อยด้วย SUSE Linux ดูเหมือนกับ:
read -e -p "Enter your choice: " choice
-e
ตัวเลือกที่ช่วยให้ผู้ใช้แก้ไขการป้อนข้อมูลที่ใช้ปุ่มลูกศร
หากคุณต้องการใช้คำแนะนำเป็นอินพุต:
read -e -i "yes" -p "Enter your choice: " choice
-i
ตัวเลือกพิมพ์อินพุตที่มีการชี้นำ
-e
-i
จะไม่ได้ทำงานในการดวลจุดโทษ (บอร์นเปลือก) แต่คำถามคือทุบตีที่ติดแท็กโดยเฉพาะ ..
คุณสามารถใช้ค่าเริ่มต้นREPLY
ใน a read
, แปลงเป็นตัวพิมพ์เล็กและเปรียบเทียบกับชุดของตัวแปรที่มีนิพจน์
สคริปต์ยังสนับสนุนja
/ si
/oui
read -rp "Do you want a demo? [y/n/c] "
[[ ${REPLY,,} =~ ^(c|cancel)$ ]] && { echo "Selected Cancel"; exit 1; }
if [[ ${REPLY,,} =~ ^(y|yes|j|ja|s|si|o|oui)$ ]]; then
echo "Positive"
fi
เป็นไปได้ที่จะจัดการกับโลแคล "Yes / No choice" ใน POSIX เชลล์ โดยใช้รายการของLC_MESSAGES
หมวดหมู่โลแคลแม่มดจัดทำรูปแบบ RegEx สำเร็จรูปเพื่อจับคู่อินพุตและสตริงสำหรับใช่ไม่ใช่
#!/usr/bin/env sh
# Getting LC_MESSAGES values into variables
# shellcheck disable=SC2046 # Intended IFS splitting
IFS='
' set -- $(locale LC_MESSAGES)
yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5" # unused here, but kept as documentation
# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"
# Read answer
read -r yn
# Test answer
case "$yn" in
# match only work with the character class from the expression
${yesexpr##^}) echo "answer $yesstr" ;;
${noexpr##^}) echo "answer $nostr" ;;
esac
แก้ไข: ตามที่@Urhixidurพูดถึงในความคิดเห็นของเขา :
น่าเสียดายที่ POSIX ระบุเพียงสองรายการแรกเท่านั้น (ใช่แล้วและ noexpr) บน Ubuntu 16 yesstr และ nostr ว่างเปล่า
ดู: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
yesstr
และnostr
คำหลักที่เกิดเหตุและYESSTR
และNOSTR
langinfo รายการถูกก่อนนำมาใช้เพื่อตอบสนองผู้ใช้แข่งขันยืนยันและลบ ใน POSIX.1-2008 ที่yesexpr
,noexpr
,YESEXPR
และNOEXPR
ขยายการแสดงออกปกติได้เข้ามาแทนที่พวกเขา แอปพลิเคชันควรใช้เครื่องมืออำนวยความสะดวกในการรับส่งข้อความทั่วไปตามตำแหน่งที่ตั้งเพื่อออกข้อความแจ้งเตือนซึ่งรวมถึงตัวอย่างคำตอบที่ต้องการ
อีกทางเลือกหนึ่งโดยใช้สถานที่ทาง Bash:
#!/usr/bin/env bash
IFS=$'\n' read -r -d '' yesexpr noexpr _ < <(locale LC_MESSAGES)
printf -v yes_or_no_regex "(%s)|(%s)" "$yesexpr" "$noexpr"
printf -v prompt $"Please answer Yes (%s) or No (%s): " "$yesexpr" "$noexpr"
declare -- answer=;
until [[ "$answer" =~ $yes_or_no_regex ]]; do
read -rp "$prompt" answer
done
if [[ -n "${BASH_REMATCH[1]}" ]]; then
echo $"You answered: Yes"
else
echo $"No, was your answer."
fi
คำตอบนั้นถูกจับคู่โดยใช้ regexps ที่จัดไว้ให้ของสภาพแวดล้อม
หากต้องการแปลข้อความที่เหลือให้ใช้bash --dump-po-strings scriptname
เพื่อส่งออกสตริง po สำหรับการแปลภาษาท้องถิ่น:
#: scriptname:8
msgid "Please answer Yes (%s) or No (%s): "
msgstr ""
#: scriptname:17
msgid "You answered: Yes"
msgstr ""
#: scriptname:19
msgid "No, was your answer."
msgstr ""
yesexpr
และnoexpr
ในสภาพแวดล้อมของเชลล์ใช้ในการจับคู่ RegEx เฉพาะของ Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
ต่อไปนี้เป็นวิธีการที่ยาวกว่า แต่ใช้ซ้ำได้และแบบแยกส่วน
0
= ใช่และ1
= ไม่zsh
bash
โปรดทราบว่าN
เป็นตัวพิมพ์ใหญ่ กดที่นี่เพื่อกดยอมรับค่าเริ่มต้น:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
และโปรดทราบว่า[y/N]?
จะมีการต่อท้ายโดยอัตโนมัติ ยอมรับค่าเริ่มต้น "ไม่" ดังนั้นจึงไม่มีสิ่งใดสะท้อนกลับ
แจ้งอีกครั้งจนกว่าจะได้รับการตอบสนองที่ถูกต้อง:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
โปรดทราบว่าY
เป็นตัวพิมพ์ใหญ่:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
ด้านบนฉันเพิ่งกด Enter ดังนั้นคำสั่งจึงรัน
y
หรือn
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
ที่นี่1
หรือเท็จถูกส่งกลับ โปรดทราบว่าด้วยฟังก์ชั่นระดับต่ำกว่านี้คุณจะต้องให้[y/n]?
พรอมต์ของคุณเอง
# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
local REPLY IFS=
>/dev/tty printf '%s' "$*"
[[ $ZSH_VERSION ]] && read -rk1 # Use -u0 to read from STDIN
# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
[[ $BASH_VERSION ]] && </dev/tty read -rn1
printf '%s' "$REPLY"
}
# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
local prompt="${1:-Are you sure [y/n]? }"
local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "
while REPLY=$(get_keypress "$prompt"); do
[[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
case "$REPLY" in
Y|y) return 0;;
N|n) return 1;;
'') [[ $enter_return ]] && return "$enter_return"
esac
done
}
# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt" 1
}
# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt" 0
}
Show dangerous command [y/N]? [y/n]?
และShow dangerous command [Y/n]? [y/n]?
ขออภัยที่โพสต์ข้อความเก่า ๆ เมื่อหลายสัปดาห์ก่อนฉันพบปัญหาที่คล้ายกันในกรณีของฉันฉันต้องการโซลูชันที่ใช้งานได้กับโปรแกรมติดตั้งออนไลน์เช่น: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
หวังว่านี่จะช่วยใครซักคน
tty
อินพุตเช่นเดียวกับคุณและสำหรับการป้อนข้อมูลที่ไม่ดี (ลองจินตนาการถึงอักขระสองสามตัวในบัฟเฟอร์วิธีการของคุณจะบังคับให้ผู้ใช้เลือกไม่เสมอ )
ฉันสังเกตเห็นว่าไม่มีใครโพสต์คำตอบที่แสดงเมนู echo หลายบรรทัดสำหรับการป้อนข้อมูลผู้ใช้อย่างง่ายดังนั้นนี่คือสิ่งที่ฉันทำได้:
#!/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
วิธีนี้ถูกโพสต์ด้วยความหวังว่าบางคนอาจพบว่ามีประโยชน์และประหยัดเวลา
รุ่นหลายตัวเลือก:
ask () { # $1=question $2=options
# set REPLY
# options: x=..|y=..
while $(true); do
printf '%s [%s] ' "$1" "$2"
stty cbreak
REPLY=$(dd if=/dev/tty bs=1 count=1 2> /dev/null)
stty -cbreak
test "$REPLY" != "$(printf '\n')" && printf '\n'
(
IFS='|'
for o in $2; do
if [ "$REPLY" = "${o%%=*}" ]; then
printf '\n'
break
fi
done
) | grep ^ > /dev/null && return
done
}
ตัวอย่าง:
$ ask 'continue?' 'y=yes|n=no|m=maybe'
continue? [y=yes|n=no|m=maybe] g
continue? [y=yes|n=no|m=maybe] k
continue? [y=yes|n=no|m=maybe] y
$
มันจะตั้งค่าREPLY
เป็นy
(ภายในสคริปต์)
ฉันแนะนำให้คุณใช้กล่องโต้ตอบ ...
Linux Apprentice: ปรับปรุง Bash Shell Script โดยใช้ Dialog
คำสั่งการโต้ตอบช่วยให้การใช้กล่องหน้าต่างในเชลล์สคริปต์เพื่อให้การใช้งานโต้ตอบมากขึ้น
มันง่ายและใช้งานง่ายนอกจากนี้ยังมี gnome รุ่นที่เรียกว่า gdialog ซึ่งใช้พารามิเตอร์เดียวกัน แต่แสดงสไตล์ GUI บน X
แรงบันดาลใจจากคำตอบของ @Mark และ @Myrddin ฉันสร้างฟังก์ชั่นนี้ขึ้นมาเพื่อให้เป็นสากล
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
}
วิธีการหนึ่งที่ง่ายที่จะทำนี้จะมีxargs -p
หรือ parallel --interactive
GNU
ฉันชอบพฤติกรรมของ xargs ที่ดีขึ้นเล็กน้อยเพราะมันดำเนินการแต่ละคำสั่งทันทีหลังจากพรอมต์เช่นคำสั่ง unix เชิงโต้ตอบอื่น ๆ แทนที่จะรวบรวม yesses ให้ทำงานในตอนท้าย (คุณสามารถ Ctrl-C หลังจากผ่านสิ่งที่คุณต้องการ)
เช่น,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
xargs --interactive
จำกัด อยู่ที่ใช่หรือไม่ ตราบใดที่คุณต้องการนั่นก็เพียงพอแล้ว แต่คำถามเดิมของฉันให้ตัวอย่างกับผลลัพธ์ที่เป็นไปได้สามแบบ ฉันชอบที่มันสามารถสตรีมได้ สถานการณ์ทั่วไปจำนวนมากจะได้รับประโยชน์จากความสามารถในการทำ piped
ในฐานะเพื่อนของคำสั่งหนึ่งบรรทัดฉันใช้สิ่งต่อไปนี้:
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=;
longform ที่เขียนใช้งานได้เช่นนี้:
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=;
ฉันเคยใช้case
คำสั่งสองสามครั้งในสถานการณ์เช่นนี้การใช้กรณีศึกษาเป็นวิธีที่ดีในการพิจารณา การwhile
วนรอบที่รวมการcase
บล็อกซึ่งใช้เงื่อนไขบูลีนสามารถนำมาใช้เพื่อควบคุมโปรแกรมได้มากขึ้นและตอบสนองความต้องการอื่น ๆ อีกมากมาย หลังจากตรงตามเงื่อนไขทั้งหมดแล้วbreak
สามารถใช้a ซึ่งจะผ่านการควบคุมกลับไปยังส่วนหลักของโปรแกรม นอกจากนี้เพื่อให้เป็นไปตามเงื่อนไขอื่น ๆ สามารถเพิ่มคำสั่งแบบมีเงื่อนไขของหลักสูตรเข้ากับโครงสร้างการควบคุม: case
คำสั่งและwhile
ลูปที่เป็นไปได้
ตัวอย่างการใช้case
คำสั่งเพื่อตอบสนองคำขอของคุณ
#! /bin/sh
# For potential users of BSD, or other systems who do not
# have a bash binary located in /bin the script will be directed to
# a bourne-shell, e.g. /bin/sh
# NOTE: It would seem best for handling user entry errors or
# exceptions, to put the decision required by the input
# of the prompt in a case statement (case control structure),
echo Would you like us to perform the option: "(Y|N)"
read inPut
case $inPut in
# echoing a command encapsulated by
# backticks (``) executes the command
"Y") echo `Do something crazy`
;;
# depending on the scenario, execute the other option
# or leave as default
"N") echo `execute another option`
;;
esac
exit
#!/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
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!'
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
ในการตอบสนองต่อผู้อื่น:
คุณไม่จำเป็นต้องระบุตัวพิมพ์ใน BASH4 เพียงใช้ ',,' เพื่อสร้างตัวพิมพ์เล็ก นอกจากนี้ฉันไม่ชอบวางโค้ดในบล็อกการอ่านรับผลลัพธ์และจัดการกับมันนอก IMO บล็อกการอ่าน รวมถึง 'q' เพื่อออกจาก IMO สุดท้ายทำไมพิมพ์ 'ใช่' เพียงแค่ใช้ -n1 และกด y
ตัวอย่าง: ผู้ใช้สามารถกด y / n และ q เพื่อเพิ่งออก
ans=''
while true; do
read -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 ans
case ${ans,,} in
y|n|q) break;;
*) echo "Answer y for yes / n for no or q for quit.";;
esac
done
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; then
echo "OK Quitting, we will assume that he is"
exit 0
fi
if [[ "${ans,,}" == "y" ]] ; then
echo "MikeQ is the greatest!!"
else
echo "No? MikeQ is not the greatest?"
fi
เวลาส่วนใหญ่ในสถานการณ์ดังกล่าวคุณต้องดำเนินการสคริปต์จนกว่าผู้ใช้จะป้อน "ใช่" และจะต้องหยุดเมื่อผู้ใช้เข้าสู่ "ไม่" ตัวอย่างด้านล่างจะช่วยให้คุณประสบความสำเร็จ!
#!/bin/bash
input="yes"
while [ "$input" == "yes" ]
do
echo "execute script functionality here..!!"
echo "Do you want to continue (yes/no)?"
read input
done
[yn]
ตัวเลือกตัวเลือกที่เป็นตัวพิมพ์ใหญ่นั้นจะเป็นค่าเริ่มต้นเช่น[Yn]
ค่าเริ่มต้นคือ"ใช่" และ[yN]
ค่าเริ่มต้นเป็น "ไม่" ดูux.stackexchange.com/a/40445/43532