Shell 脚本 - 数字检查和 if 语句问题

时间:2021-05-03 19:41:15

标签: bash shell loops if-statement terminal

我在这里和编码世界相对较新。我目前正在学习 Shell Scripting 课程,但有点卡住了。

我正在尝试做一些额外的功劳,让脚本检查命令行参数,如果没有或只有 1,则提示用户输入缺失的值。

在大多数情况下,除了数字检查部分之外,我已经能够使其大部分工作。我不完全确定我是否正确执行了嵌套的 if 语句,因为它同时显示了“if”回声和“else”回声。

到目前为止我的脚本:

q=y
# Begins loop
until [[ $q == n ]];do
    # Checks command line arguments
    if [[ $# -lt 2 ]];then
        # Asks for second number if only 1 argument.
        if [[ $# == 1 ]];then
            read -r -p "Please enter your second number: " y
            if [[ y =~ [1-9] ]];then
                echo "You've chosen $1 as your first number and $y as your second number."
                break
            else
                echo "This is not a valid value, please try again."
            fi
        # Asks for both numbers if no arguments.
        else
            read -r -p "Please enter your first number: " x
            if [[ x =~ [1-9] ]];then
                break
            else
                echo "This is not a valid value, please try again."
            fi
            read -r -p "Please enter your second number: " y
            if [[ y =~ [1-9] ]];then
                break
            else
                echo "This is not a valid value, please try again."
            fi
        echo "You've chosen $x as your first number and $y as your second number."
        fi
    # If both command line arguments are provided, echo's arguments, and sets arguments as x and y values.
    else
        echo "You've chosen $1 as your first number and $2 as your second number."
        x=$1
        y=$2
    fi
    read -r -p "Would you like to try again? (n to exit): " q
done

当我运行它时,我得到了这个输出:

Please enter your first number: 1
This is not a valid value, please try again.
Please enter your second number: 2
This is not a valid value, please try again.
You've chosen 1 as your first number and 2 as your second number.
Please enter your first number: 

并且将继续循环而不中断。任何帮助/指导将不胜感激,谢谢。

2 个答案:

答案 0 :(得分:3)

在你的表达中:

if [[ x =~ [1-9] ]]; then

您实际上是在将字符串文字“x”与正则表达式进行比较。你想要的是变量:

if [[ $x =~ [1-9] ]]; then

这将首先插入变量,以便将变量的值与正则表达式进行比较。我认为此更改也适用于您代码中的其他一些比较表达式。

但是,正如 glenn jackman 和 user1934428 所评论的,这也将匹配 foo1bar 之类的内容,这可能不是您想要的。要解决此问题,您可以向正则表达式添加开始/结束匹配器。最后,即使输入有前导或尾随空格,您也可能希望进行匹配。一种方法是添加一些 [[:space:]]* 以匹配 [1-9] 周围的零个或多个空格:

 if [[ $x =~ ^[[:space:]]*[1-9][[:space:]]*$ ]]; then

所以,分解正则表达式:

  • ^ 开始输入
  • [[:space:]]* 零个或多个空格
  • [1-9] 一位数,1-9
  • [[:space:]]* 零个或多个空格
  • $ 输入结束

我从您的问题中假设您只想匹配单个数字,而不是例如 12 或数字 0。要匹配这些需要更多的正则表达式调整。

和...全局模式

仅仅因为 glen jackman's answer 带领我进行了 bash 手册页冒险? 并且我想尝试一下,这是一个 glob 模式版本(注意 == 而不是 =~):

if [[ $x == *([[:space:]])[1-9]*([[:space:]]) ]]; then

这基本上是相同的模式。但值得注意的是,glob 模式似乎是 implicitly anchored to the start/end of the string being matched(它们针对整个字符串进行测试),因此它们不需要 ^$,而 regular expressions match against substrings by default,因此它们确实需要这些添加来避免 foo1bar 匹配。无论如何,可能比你想知道的要多。

答案 1 :(得分:2)

这是一个替代实现,供您考虑:有任何问题都可以找我

#!/usr/bin/env bash

get_number() {
    local n
    while true; do
        read -rp "Enter a number between 1 and 9: " n
        if [[ $n == [1-9] ]]; then
            echo "$n"
            return
        fi
    done
}

case $# in
    0)  first=$(get_number)
        second=$(get_number)
        ;;
    1)  first=$1
        second=$(get_number)
        ;;
    *)  first=$1
        second=$2
        ;;
esac

# or, more compact but harder to grok
[[ -z  ${first:=$1} ]] &&  first=$(get_number)
[[ -z ${second:=$2} ]] && second=$(get_number)


echo "You've chosen $first as your first number and $second as your second number."

这使用:

  • 一个从用户那里获取一个数字的函数,这样你就没有那么多重复的代码了,
  • 用于切换 case 变量的 $# 语句
  • 使用 == 中的 [[...]] 运算符进行输入验证——此运算符是一个模式匹配运算符,而不是字符串相等(除非右侧操作数被引用)< /li>

请注意,[[ $x =~ [1-9] ]] 表示:“$x 包含 1 到 9 范围内的一个字符”——它表示变量 一个数字。如果 x=foo1bar,则正则表达式测试通过。