【问题标题】:Counting the number of inputs provided by user计算用户提供的输入数量
【发布时间】:2020-05-05 23:27:24
【问题描述】:

描述:我有一个脚本,它以向用户提出的警告/问题开头。我需要用户回答yes/y 或no/n。

问题:虽然我有一个条件来确保用户提供上面提供的以下答案之一,但我还需要确保用户只提供一个输入。我曾尝试使用

[ "$#" -eq 1 ][ $# -eq 1 ] 这些条件似乎都不能解决问题

这是我目前所拥有的:...

#!/bin/bash
#
# Descritpion: some Windows OS script
#
# 

printf "(!)WARNING(!): 1. The this program is ONLY compatible with Windows operating systems. "
printf "2. You will NEED to be logged in as an ADMIN in order to fully make use of the '*****' script.\n" 
printf "Would you like to continue? yes or no (y/n): "

#would it be cleaner to use "case" rather than a "while" w/ multiple conditionals? (01.19.2020)
read opt

while (true)
do
        if [ $opt == yes ] || [ $opt == y ]
        then
                printf "continue. \n"
                break

        elif [ $opt == no ] || [ $opt == n ]
        then
                printf "OK, exiting the script! \n"
                exit 0

        #elif [ "$#" -ne 1 ]
        #then
        #       "Too many arguments have been provided, please try again. \n"
        #       read opt
        else
                printf "The opition you provided is not recognized, please try again. \n"
                read opt
        fi
done

【问题讨论】:

  • only ONE input is provided by the use - 请举例说明应该发生什么。 “一个输入”是什么意思?什么是“双输入”?

标签: linux bash if-statement conditional-statements git-bash


【解决方案1】:

不是理想的解决方案,但它解释了为什么 $# 无法按预期工作:

$# 返回传递给函数的参数数量。您已将“选择”作为用户输入阅读 - 而不是函数的参数。

一种解决方案可能是将无限 while 循环包装在一个函数中,然后将 $opt 传递给它。然后它将成为您的函数的参数,您可以使用 $# 来计算有多少。 有关 bash 中许多内置函数的工作原理的详细信息,您可以尝试:

man bash

但我接受其中有很多信息。您可以搜索相关单词,通常使用“/{searchstring}”(但您可能需要“转义”特殊字符,在这种情况下:“/\$\#”)

【讨论】:

  • 正如@Diego 所说, read 有多种选择 - 使用“-a”要求它读入数组将对您有所帮助。然后您可以使用“参数扩展”(在 bash 手册页中查找该部分)。这是一个小脚本,我在阅读了更多手册页后才将它放在一起:#!/bin/bash declare -a opt read -a opt echo "opt: ${opt}, count: ${#opt[ *]}" 当我运行这个脚本时,我可以输入:测试二三,它会响应:opt: test, count: 3
  • 抱歉,这是我的第一个 SE 评论,我正在为格式化而苦苦挣扎,无法再编辑它(5 分钟后)。我以为我有
      块,但我一定误解了。上面脚本的重要部分是read -a opt 行和echo "opt: ${opt}, count: ${#opt[*]}" 行。最后一部分是参数扩展,将 opt 数组替换为数组中当前元素的数量。感谢@Diego 的轻推。我没有评论你的回答,因为我还不能...... :-)
【解决方案2】:

看看read选项

读取:读取 [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]

从标准输入或文件描述符 FD 中读取一行,如果 提供 -u 选项,并将第一个单词分配给第一个 NAME, 第二个单词到第二个名字,依此类推,剩下的单词被分配 到最后一个 NAME。只有 $IFS 中的字符被识别为单词 分隔符。如果没有提供 NAME,则读取的行存储在 REPLY 多变的。如果给出 -r 选项,这表示“原始”输入,并且 反斜杠转义被禁用。 -d 选项使读取继续 直到读取 DELIM 的第一个字符,而不是换行符。如果 -p 提供选项时,输出字符串 PROMPT,不带尾随换行符 在尝试阅读之前。如果提供了 -a,则分配读取的单词 到数组的顺序索引,从零开始。如果提供了 -e 并且 shell 是交互式的,readline 用于获取行。如果 -n 是 提供非零 NCHARS 参数,在 NCHARS 之后读取返回 字符已被读取。 -s 选项导致输入来自 终端不被回显。

您可以使用其中的一些来简化您的脚本。

【讨论】:

    【解决方案3】:

    读取输入并准确解析。决定是否要忽略空格。您甚至可以使用正则表达式将输入格式化为您想要的格式。

    1. while (true) 是对子shell 的不必要使用。只需while true
    2. 如果opt 包含空格,则if [ $opt == yes ] 将不起作用,例如用户输入y e s。它将以非零退出状态退出并在标准错误流上打印错误消息。作为一项规则,总是引用你的变量扩展。总是"$opt",从不$opt。这很可能是您要求修复的错误。
    3. == 也是一个 bash 扩展。使用= 进行字符串比较。
    4. 化妆品:[ $opt == yes ] || [ $opt == y ] 不必要的运行两个进程以防第一个进程失败。只需运行一个进程[ "$opt" = yes -o "$opt" = y ]。但第一个可能更清楚。
    5. read opt 忽略前导和尾随空格并删除 \ 斜杠。使用IFS= read -r opt 完全按原样阅读整行。
    6. 使用 shellcheck.net 检查您的脚本。
    7. $# 是传递给脚本的参数数量。它与read 的作用无关。 read 将输入保存到变量中。

    所以:

    while true; do
       if ! IFS= read -r opt; then
          echo "ERROR: END OF INPUT!" >&2
          exit 2
       fi
       case "$opt" in
       y|yes) printf 'continue. \n'; break; ;;
       n|no) printf 'OK, exiting the script! \n'; exit 1; ;;
       *) printf 'The opition you provided is not recognized, please try again. \n'; ;;
       esac
    done
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多