【问题标题】:Check existence of input argument in a Bash shell script检查 Bash shell 脚本中是否存在输入参数
【发布时间】:2011-09-22 20:48:51
【问题描述】:

我需要检查输入参数是否存在。我有以下脚本

if [ "$1" -gt "-1" ]
  then echo hi
fi

我明白了

[: : integer expression expected

如何先检查输入参数 1 是否存在?

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    它是:

    if [ $# -eq 0 ]
      then
        echo "No arguments supplied"
    fi
    

    $# 变量将告诉您脚本传递的输入参数的数量。

    或者您可以检查参数是否为空字符串:

    if [ -z "$1" ]
      then
        echo "No argument supplied"
    fi
    

    -z 开关将测试"$1" 的扩展是否为空字符串。如果是空字符串,则执行正文。

    【讨论】:

    • 我喜欢这样做,语法简洁,而且仍然可以接受 POSIX。 [ -z "$1" ] && echo "No argument supplied" 我更喜欢单线,因为它们对我来说更容易;与使用 if 相比,检查退出值也更快
    • 当脚本运行需要参数时,您可能希望在 if 块内的回显末尾添加 exit 1。显而易见,但值得注意的是完整性。
    • 第一个参数被初始化但为空是可能的,虽然很少有用; programname "" secondarg third$# 检查明确检查参数的数量。
    • 对于菜鸟,尤其是非脚本背景的人来说,提及这些事情的一些特殊性也很重要。您还可以提到我们需要在左大括号和右大括号之后留一个空格。否则事情不工作。我自己是一个脚本菜鸟(我来自 C 背景)并且发现它很难。只有当我决定“按原样”复制整个事情时,事情才对我有用。就在那时我意识到我必须在左大括号之后和右大括号之前留出一个空间。
    • 对于可选参数if [ ! -z "$1" ]; then ...
    【解决方案2】:

    另一种检测参数是否传递给脚本的方法:

    ((!$#)) && echo No arguments supplied!
    

    请注意,(( expr )) 会导致表达式按照 Shell Arithmetic 的规则进行评估。

    为了在没有任何参数的情况下退出,可以说:

    ((!$#)) && echo No arguments supplied! && exit 1
    

    另一种 (类似的) 说法是:

    let $# || echo No arguments supplied
    
    let $# || { echo No arguments supplied; exit 1; }  # Exit if no arguments!
    

    help let 说:

    let: let arg [arg ...]

      Evaluate arithmetic expressions.
    
      ...
    
      Exit Status:
      If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
    

    【讨论】:

    • -1 如果验证参数的存在,这可能是最糟糕的方法。而且它可能会触发历史替换并可能做坏事。
    • 而不是 exit 杀死我的 zsh 进程,我使用 return 不会杀死它
    • 为什么((!$#)) 会触发历史记录替换?
    【解决方案3】:

    试试:

     #!/bin/bash
     if [ "$#" -eq  "0" ]
       then
         echo "No arguments supplied"
     else
         echo "Hello world"
     fi
    

    【讨论】:

    • 为什么$#0 需要双引号?
    • 如果我们使用不带双引号的 $# 和 0 也没问题
    • 在 Windows 上,mingw 这是唯一的方法。
    • 这个答案为我刚刚制作的脚本提供了很好的起点。感谢您也显示else
    • @user13107 bash 中的双引号变量可防止通配符(即扩展文件名,如foo*)和分词(即,如果值包含空格,则拆分内容)。在这种情况下,没有必要引用$#,因为这两种情况都不适用。引用 0 也不是必须的,但有些人更喜欢引用值,因为它们实际上是字符串,这使得它更加明确。
    【解决方案4】:

    提醒一下,Bash 中的数字测试运算符仅适用于整数(-eq-lt-ge 等)

    我喜欢确保我的 $vars 是整数

    var=$(( var + 0 ))
    

    在我测试它们之前,只是为了防止出现“[: integer arg required”错误。

    【讨论】:

    • 巧妙的技巧,但请注意:由于 bash 无法处理算术中的浮点数,此方法可能会导致语法错误并返回非零值,这将成为启用 errexit 的障碍。 var=$(printf "%.0f" "$var") 可以处理浮点数,但在给定字符串时会出现非零退出。如果您不介意 awk,我使用的这种方法似乎是执行整数的最可靠的方法:var=$(<<<"$var" awk '{printf "%.0f", $0}')。如果 var 未设置,则默认为“0”。如果 var 是浮点数,则四舍五入到最接近的整数。负值也可以使用。
    【解决方案5】:

    最好这样演示

    if [[ $# -eq 0 ]] ; then
        echo 'some message'
        exit 1
    fi
    

    如果参数太少,通常需要退出。

    【讨论】:

    • 不,不是:这具有您通常想要的exit 1,并使用通常更合理的[[ ]] 测试。所以对于盲目复制粘贴代码的人来说,这是更好的答案。
    • 要了解更多关于 [ ] 和 [[ ]] 之间的区别,请参阅stackoverflow.com/questions/3427872/…
    【解决方案6】:

    在某些情况下,您需要检查用户是否向脚本传递了参数,如果没有,则回退到默认值。就像在下面的脚本中一样:

    scale=${2:-1}
    emulator @$1 -scale $scale
    

    如果用户没有将scale 作为第二个参数传递,我默认使用-scale 1 启动Android 模拟器。 ${varname:-word} 是扩展运算符。还有其他扩展运算符:

    • ${varname:=word} 设置未定义的 varname 而不是返回 word 值;
    • ${varname:?message} 如果已定义且不为空,则返回 varname 或打印 message 并中止脚本(如第一个示例);
    • ${varname:+word} 仅当 varname 已定义且不为空时才返回 word;否则返回 null。

    【讨论】:

    • 上面的例子似乎使用了${varname?message}。额外的: 是拼写错误,还是会改变行为?
    • Eki,“:”是一个内置命令,在这个例子中是 /bin/true 的简写。它代表一个什么都不做的命令,基本上忽略它提供的参数。为了防止解释器尝试执行“$varname”的内容(您当然不希望发生这种情况),在此测试中必须这样做。也值得注意;您可以根据需要使用此方法测试尽可能多的变量。并且都带有特定的错误消息。即: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
    【解决方案7】:

    如果您想检查参数是否存在,您可以检查参数的数量是否大于或等于您的目标参数数。

    以下脚本演示了它是如何工作的

    test.sh

    #!/usr/bin/env bash
    
    if [ $# -ge 3 ]
    then
      echo script has at least 3 arguments
    fi
    

    产生以下输出

    $ ./test.sh
    ~
    $ ./test.sh 1
    ~
    $ ./test.sh 1 2
    ~
    $ ./test.sh 1 2 3
    script has at least 3 arguments
    $ ./test.sh 1 2 3 4
    script has at least 3 arguments
    

    【讨论】:

      【解决方案8】:

      我经常将这个 sn-p 用于简单的脚本:

      #!/bin/bash
      
      if [ -z "$1" ]; then
          echo -e "\nPlease call '$0 <argument>' to run this command!\n"
          exit 1
      fi
      

      【讨论】:

      • 那么,这是用在你只需要一个参数吗?
      • @Danijel 不,这是测试第一个位置是否有参数。您可以有一个 $2 或 $3 参数($0 是正在运行的脚本名称)。这只是忽略传递的任何其他参数。
      【解决方案9】:

      只是因为有一个更基点要指出,我要补充一点,你可以简单地测试你的字符串是否为空:

      if [ "$1" ]; then
        echo yes
      else
        echo no
      fi
      

      同样,如果您期望 arg 计数,只需测试您的最后一个:

      if [ "$3" ]; then
        echo has args correct or not
      else
        echo fixme
      fi
      

      任何 arg 或 var 以此类推

      【讨论】:

        【解决方案10】:

        单行 bash 函数验证

        myFunction() {
        
            : ${1?"forgot to supply an argument"}
            if [ "$1" -gt "-1" ]; then
                echo hi
            fi
        
        }
        

        添加函数名称和用法

        myFunction() {
        
            : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"}
            if [ "$1" -gt "-1" ]; then
                echo hi
            fi
        
        }
        

        添加验证以检查是否为整数

        要添加额外的验证,例如检查传递的参数是否为整数,修改验证一行以调用验证函数:

        : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"
        

        然后,构造一个验证函数来验证参数,成功时返回 0,失败时返回 1,失败时中止脚本的 die 函数

        validateIntegers() {
        
            if ! [[ "$1" =~ ^[0-9]+$ ]]; then
                return 1 # failure
            fi
            return 0 #success
        
        }
        
        die() { echo "$*" 1>&2 ; exit 1; }
        

        更简单 - 只需使用 set -u

        set -u 确保在使用时设置每个引用的变量,所以只需设置它并忘记它

        myFunction() {
            set -u
            if [ "$1" -gt "-1" ]; then
                echo hi
            fi
        
        }
        

        【讨论】:

          【解决方案11】:

          在我的情况下,检查 last arguments 是否存在的唯一可行解决方案是:

          if [[ "$7" == '' ]] ; then
            echo "error"
            exit
          fi
          

          【讨论】:

          • 这不是真的。 $7 是第 7 个参数(如果算上脚本名称 $0,则为第 8 个),所以这不会检查最后一个参数是否存在,它会检查第 7 个参数是否存在。
          • 我确实同意这不是问题的解决方案,并且是不同(并且可能是可以避免的)问题的次优解决方案。七个位置论据似乎很重。另外,没有退出状态的exit 会返回echo "error" 的退出状态,我预计是零。推荐shellcheckset -euo pipefail。我现在要停下来......
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-20
          • 2021-11-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多