我想暂停shell脚本中的输入,并提示用户进行选择。标准的是、否或取消类型问题。如何在典型的bash提示符中完成此操作?


当前回答

此解决方案读取单个字符,并在yes响应时调用函数。

read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    do_something      
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

我是一个初学者,所以要谨慎对待,但它似乎奏效了。

这个问题有很多很好的答案,但从我看来,没有一个是我的理想,那就是:

简单一点,只需要几行外壳使用单个y/n键(无需按enter键)如果只按回车键,则默认为yes也可以使用大写的Y/N

这是我的版本,它具有这些财产:

read -n1 -p "Continue? (Y/n) " confirm

if ! echo $confirm | grep '^[Yy]\?$'; then
  exit 1
fi

如果要在两个分支上运行代码,可以修改该条件,使其仅在“yes”上运行(只需删除if语句中的!)或添加else。

我注意到,对于这样简单的用户输入,没有人发布显示多行回声菜单的答案,所以我的做法如下:

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

发布这种方法是希望有人发现它有用且省时。

您可以编写一个函数来测试:

confirm() {
  local ans IFS=;
  while read -rp "$1" -n1 ans;
  do printf '\n';
    case $ans in [Yy]) return 0;;
      [Nn]) return 1;;
    esac;
  done;
}; ## Usage: if confirm "Are you sure? "; then ...

if confirm "Does everything look ok...reboot now? [Y/n]"; then
  echo "rebooting..."
  sleep 5
  reboot
fi

可以在POSIX shell中处理区域设置感知的“是/否选项”;通过使用LC_MESSAGES语言环境类别的条目,witch提供了与输入匹配的现成RegEx模式,以及本地化Yes No的字符串。

#!/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只指定了前两个(yeexpr和noexpr)。在Ubuntu 16上,yestr和nostr为空。

参见:https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V_4_xbd_chap07.html#tag_21_07_03_06

LC_消息yestr和nostr语言环境关键字以及yesstr和nostr语言信息项以前用于匹配用户的肯定和否定响应。在POSIX.1-2008中,yeexpr、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

使用语言环境提供的regexp来匹配答案。

要翻译剩余的消息,请使用bash--dump po string 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 ""