How do I prompt for Yes/No/Cancel input in a Linux shell script?

后端 未结 30 2395
不思量自难忘°
不思量自难忘° 2020-11-22 04:52

I want to pause input in a shell script, and prompt the user for choices.
The standard Yes, No, or Cancel type question.
How d

30条回答
  •  面向向阳花
    2020-11-22 05:04

    It is possible to handle a locale-aware "Yes / No choice" in a POSIX shell; by using the entries of the LC_MESSAGES locale category, witch provides ready-made RegEx patterns to match an input, and strings for localized 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
    

    EDIT: As @Urhixidur mentioned in his comment:

    Unfortunately, POSIX only specifies the first two (yesexpr and noexpr). On Ubuntu 16, yesstr and nostr are empty.

    See: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06

    LC_MESSAGES

    The yesstr and nostr locale keywords and the YESSTR and NOSTR langinfo items were formerly used to match user affirmative and negative responses. In POSIX.1-2008, the yesexpr, noexpr, YESEXPR, and NOEXPR extended regular expressions have replaced them. Applications should use the general locale-based messaging facilities to issue prompting messages which include sample desired responses.

    Alternatively using locales the Bash way:

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

    The answer is matched using locale environment's provided regexps.

    To translate the remaining messages, use bash --dump-po-strings scriptname to output the po strings for localization:

    #: 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 ""
    

提交回复
热议问题