variable 如何在Linux shell腳本中提示是/否/取消輸入?




ubuntu shell script (20)

我想在shell腳本中暫停輸入,並提示用戶進行選擇。 標準的“是,否,或取消”類型問題。 我如何在典型的bash提示符下完成此操作?


該解決方案讀取單個字符並在yes響應中調用函數。

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

在shell提示下獲取用戶輸入的最簡單和最廣泛的方法是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指出的方法是Bash的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循環來重試。

另外,請查看F. Hauri的優秀答案 。


以最少的行數實現這個最簡單的方法如下:

read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;

if [ "$CONDITION" == "y" ]; then
   # do something here!
fi

if僅僅是一個例子:如何處理這個變量取決於你。


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?"

...

echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"

一個通用問題至少有五個答案。

取決於

  • 符合posix :可以在通用shell環境下運行在較差的系統上
  • bash具體:使用所謂的bashisms

如果你想

  • 簡單``在線''問題/答案(通用解決方案)
  • 相當格式化的接口,如ncurses或更多圖形使用libgtk或libqt ...
  • 使用強大的readline歷史記錄功能

1. POSIX通用解決方案

你可以使用read命令,接下來是if ... then ... else

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

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

#(感謝Adam Katz的評論 :這個測試更便攜,避免一個分叉:)

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

POSIX,但單一的關鍵功能

但是如果你不希望用戶必須點擊返回 ,你可以寫:

編輯:正如@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

注意:這是在sh , bash , ksh , dash和busybox !

相同,但是明確地等待yn

#/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

使用專用工具

有許多工具是使用libncurseslibgtklibqt或其他圖形庫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 ,對話框的寬度是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 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

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

這將在你的$HOME目錄中創建一個.myscript.history文件,比你可以使用readline的歷史命令,比如UpDownCtrl + r等等。


我注意到,沒有人發布了一個答案,顯示了這樣簡單的用戶輸入的多行迴聲菜單,所以這裡是我去的地方:

#!/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 alright? (y/n) " RESP
if [ "$RESP" = "y" ]; then
  echo "Glad to hear it"
else
  echo "You need more bash programming"
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

然後是所有你需要的其他東西


是/否/取消

功能

#!/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

作為單行命令的朋友,我使用了以下內容:

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 case語句,使用case statment是一個很好的解決方法。 一個while循環可以實現一個利用布爾條件的case塊來實現對程序的更多控制,並滿足許多其他需求。 在滿足所有條件之後,可以使用一個break來將控制權交還給程序的主要部分。 此外,為了滿足其他條件,當然可以添加條件語句以伴隨控制結構: 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

更通用的是:

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
}

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

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

-e選項使用戶能夠使用箭頭鍵編輯輸入。

如果你想使用建議作為輸入:

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

-i選項打印一個暗示輸入。


一個簡單的方法是使用xargs -p或gnu parallel --interactive

我喜歡xargs的行為,因為它會像其他交互式unix命令一樣,在提示符後立即執行每條命令,而不是收集最後運行的yesses。 (你可以通過Ctrl-C來完成你想要的。)

例如,

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

受@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"

你要:

  • Bash內建命令(即便攜式)
  • 檢查TTY
  • 默認答案
  • 時間到
  • 彩色的問題

片段

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 ... =>如果TTY read調用命令
  • read -n 1 =>等待一個字符
  • $'\e[1;32m ... \e[0m ' =>以綠色打印
    (綠色很好,因為在白色/黑色背景上都可讀)
  • [[ $do_xxxx =~ ^(y|Y|)$ ]] => bash正則表達式

超時=>默認答案是否

do_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

抱歉張貼在這樣一個舊帖子。 幾個星期前,我遇到了類似的問題,就我而言,我需要一個解決方案,它也可以在線安裝程序腳本中使用,例如: 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

希望這可以幫助某人。


這是我放在一起的東西:

#!/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

我是一個初學者,所以拿一點鹽,但它似乎工作。





scripting