【问题标题】:Shell Scripting - Numeric Checks and if statement questionsShell 脚本 - 数字检查和 if 语句问题
【发布时间】:2021-07-26 05:12:22
【问题描述】:

我在这里和编码世界都比较陌生。我目前正在学习 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: 

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

【问题讨论】:

    标签: bash shell loops if-statement terminal


    【解决方案1】:

    在你的表达中:

    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,因此它们确实需要这些添加以避免@987654342 @匹配。无论如何,可能比你想知道的要多。

    【讨论】:

    • 谢谢,这很好。我很高兴看到在实现了 "" 和 $ 之后我能够让它工作,并看到我的 if 语句小混乱实际上嵌套正确。
    • @xdhmoore :从语法上讲,您的想法是正确的,但应用于 OP 的代码,它会认为字符串 foo25xx 与条件匹配。这不是 OP 的想法。
    • @user1934428 谢谢,我为此添加了一个额外的模式。
    【解决方案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 语句切换 $# 变量
    • 使用[[...]] 中的== 运算符进行输入验证——该运算符是模式匹配 运算符,而不是字符串相等(除非右操作数被引用)

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

    【讨论】:

    • 无论我的意见是否有价值,我都喜欢这个答案干净利落地避免了有时因尝试响应各种可能的输入而产生的“if 语句地狱”。
    • 我喜欢你使用 get_number 函数所做的事情,我不知道这是一件事,并且会在以后的项目中记住这一点,谢谢。不过,我不太了解其中的“案例”部分。 “切换” $# 变量是什么意思?
    • case 语句是否只是替换了所有的 if 和 else?你总是这样组织案例陈述吗?在那个案例陈述中假设我可以添加尽可能多的可能性是否也安全?
    • shell case 语句就像出现在许多其他语言中的switch 命令:你给它一个值(这里是$#)和几个匹配的全局模式:第一个比赛获胜。记录在案的here in the manual
    • input validation with the == operator within [[...]] -- this operator is a pattern matching operator, not string equality - 必须查一下。万一其他人感到困惑,这是 bash 手册页的模式匹配部分中的 glob 模式匹配,包括 extglob 运算符,而不是正则表达式模式匹配。尽管两者的共同点比我想象的要多……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    • 2017-05-21
    相关资源
    最近更新 更多