【问题标题】:Check number of arguments passed to a Bash script检查传递给 Bash 脚本的参数数量
【发布时间】:2013-09-05 07:06:48
【问题描述】:

如果未满足所需的参数计数,我希望我的 Bash 脚本打印一条错误消息。

我尝试了以下代码:

#!/bin/bash
echo Script name: $0
echo $# arguments 
if [$# -ne 1]; 
    then echo "illegal number of parameters"
fi

由于某些未知原因,我收到以下错误:

test: line 4: [2: command not found

我做错了什么?

【问题讨论】:

  • 你不应该将你的脚本命名为test。那是标准 Unix 命令的名称,你不会想隐藏它。
  • 在 bash 中的 if 语句中始终在 '[' ('[[') 或 '(' ('((')) 周围使用空格。
  • 要添加到@zoska 评论,您需要在 [ 之前有一个空格,因为它是作为命令实现的,请尝试 'which ['。
  • 下面的链接给出了更好的例子:stackoverflow.com/questions/4341630/…
  • @Barmar 肯定将其命名为 test,只要它不在 PATH 上就可以了?

标签: bash parameter-passing command-line-arguments


【解决方案1】:

就像任何其他简单命令一样,[ ... ]test 在其参数之间需要空格。

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters"
fi

或者

if test "$#" -ne 1; then
    echo "Illegal number of parameters"
fi

建议

在 Bash 中,更喜欢使用 [[ ]],因为它不会对其变量进行分词和路径名扩展,除非它是表达式的一部分,否则可能不需要引用。

[[ $# -ne 1 ]]

它还具有其他一些功能,例如不带引号的条件分组、模式匹配(与extglob 的扩展模式匹配)和正则表达式匹配。

以下示例检查参数是否有效。它允许一个或两个参数。

[[ ($# -eq 1 || ($# -eq 2 && $2 == <glob pattern>)) && $1 =~ <regex pattern> ]]

对于纯算术表达式,使用(( )) 可能会更好,但在[[ ]] 中仍然可以使用其算术运算符,如-eq-ne-lt-le、@ 987654344@,或-ge,将表达式作为单个字符串参数:

A=1
[[ 'A + 1' -eq 2 ]] && echo true  ## Prints true.

如果您还需要将它与[[ ]] 的其他功能结合起来,这应该会很有帮助。

请注意,[[ ]](( )) 是与 ifcasewhilefor 具有相同解析级别的关键字。

也正如Dave 所建议的那样,错误消息最好发送到stderr,这样在重定向stdout 时它们就不会被包含在内:

echo "Illegal number of parameters" >&2

退出脚本

当传递无效参数时让脚本退出也是合乎逻辑的。 ekangas 已经在 comments 中提出了这个建议,但是有人编辑了这个答案,让它以 -1 作为返回值,所以我不妨做对。

-1 虽然被 Bash 接受为 exit 的参数,但没有明确记录,也不适合用作常见建议。 64 也是最正式的值,因为它在 sysexits.h#define EX_USAGE 64 /* command line usage error */ 中定义。大多数像ls 这样的工具也会在无效参数上返回2。我也曾经在我的脚本中返回2,但最近我不再关心,只是在所有错误中使用1。但是让我们将2 放在这里,因为它是最常见的并且可能不是特定于操作系统的。

if [[ $# -ne 1 ]]; then
    echo "Illegal number of parameters" >&2
    exit 2
fi

参考文献

【讨论】:

  • OP:请记住,[ 只是另一个命令,即尝试which [
  • @Leo 命令可以内置,也可以不内置。在 bash 中,[ 是内置函数,而 [[ 是关键字。在一些较旧的 shell 中,[ 甚至不是内置的。像[ 这样的命令在大多数系统中自然地作为外部命令共存,但内部命令由 shell 优先考虑,除非你用commandexec 绕过。查看 shell 的文档以了解它们是如何评估的。记下它们的区别,以及它们在每个 shell 中的行为可能有何不同。
  • 最后一点,我建议在退出之前将错误消息写入 STDERR,然后返回错误代码。这样就可以了:(&gt;&amp;2 echo 'Illegal number of parameters')
  • @Dave 我同意,但 subshel​​l 是不必要的。
  • @timgeb 为了保持一致性。如果它不必进行分词和文件名扩展,那么无论它的扩展值是否预计不受此类过程的影响,都应该引用它。
【解决方案2】:

如果您正在处理数字,使用arithmetic expressions 可能是个好主意。

if (( $# != 1 )); then
    >&2 echo "Illegal number of parameters"
fi

&gt;&amp;2用于将错误信息写入stderr。

【讨论】:

  • 在目前的情况下,为什么这是个好主意?考虑到效率、可移植性和其他问题,最好使用最简单和最普遍理解的语法,即[ ... ],这样就可以很好地完成工作,不需要花哨的操作?
  • @Max 算术扩展 $(( )) 并不花哨,应该由所有 POSIX shell 实现。但是,(( )) 语法(没有$)不是其中的一部分。如果您由于某种原因受到限制,那么您当然可以使用[ ],但请记住,您也不应该使用[[ ]]。我希望您了解[ ] 的陷阱以及这些功能存在的原因。但这是一个 Bash 问题,所以我们给出 Bash 答案 (“As a rule of thumb, [[ is used for strings and files. If you want to compare numbers, use an ArithmeticExpression”)。
  • 出现错误时,始终写入 STDERR。 (&gt;&amp;2 echo 'Illegal number of parameters')
  • @Dave 是的。我年轻又笨:) 编辑。
【解决方案3】:

On []: !=, =, == ... 是 string 比较运算符,-eq, -gt ... 是 算术 二元运算符。

我会使用:

if [ "$#" != "1" ]; then

或者:

if [ $# -eq 1 ]; then

【讨论】:

  • == 实际上是一个未记录的功能,它碰巧与 GNU test 一起使用。它也发生适用于 FreeBSD test,但可能不适用于 foo testonly 标准比较是=(仅供参考)。
  • 在 bash man entry 中有记载:当使用 == 和 != 运算符时,运算符右边的字符串被认为是一个模式,并根据下面描述的规则进行匹配在模式匹配下。如果启用了 shell 选项 nocasematch,则执行匹配时不考虑字母字符的大小写。如果字符串匹配 (==) 或不匹配 (!=) 模式,则返回值为 0,否则为 1。可以引用模式的任何部分以强制将其作为字符串匹配。
  • @jhvaras:这正是 Carpetsmoker 所说的:它可能在某些实现中有效(实际上,它在 Bash 中有效),但 it is not POSIX-compliant。例如,它将失败并显示dashdash -c '[ 1 == 1 ]'。 POSIX 只指定=,而不是==
【解决方案4】:

如果您只对缺少特定参数的情况感兴趣,Parameter Substitution 非常棒:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT

【讨论】:

  • 这不是装满了bashisms吗?
  • @DwightSpencer 有关系吗?
  • @Temak 如果您有具体问题,我可以,但链接到的文章解释得比我好。
  • 在这一点上,当有人专门提出一个关于软件的问题(在这种情况下是 bash),然后人们抱怨回答问题的答案却使用了让生活更轻松但排他性的功能时,这只是网络幽默到那个软件。再见,我将返回 Google 表格论坛抱怨他们的回复在我的意大利本地化版本的 Office 95 上不起作用。
【解决方案5】:

可以使用以下方法完成一个简单的单行:

[ "$#" -ne 1 ] && ( usage && exit 1 ) || main

这分解为:

  1. 测试 bash 变量的参数大小 $# 不等于 1(我们的子命令数)
  2. 如果为 true,则调用 usage() 函数并以状态 1 退出
  3. 否则调用 main() 函数

注意事项:

  • usage() 可以只是简单的 echo "$0: params"
  • main 可以是一个长脚本

【讨论】:

  • 如果您在该行之后还有另一组行,那将是错误的,因为exit 1 仅适用于子shell 的上下文,使其与( usage; false ) 同义。在选项解析方面,我不喜欢这种简化方式,但您可以改用{ usage &amp;&amp; exit 1; }。或者可能只是{ usage; exit 1; }
  • @konsolebox (usage && exit 1) 适用于返回 bash 2.0 的 ksh、zsh 和 bash。 {...} 语法仅在 4.0+ 的 bash 中出现。如果一种方法适合您然后使用它,请不要误会我的意思,但请记住,并非每个人都使用与您相同的 bash 实现,我们应该按照 posix 标准而不是 bashisms 进行编码。
  • 我不确定你在说什么。 {...} 是一种通用语法,即使不是所有基于 sh 的 shell,也适用于大多数(如果不是所有)shell,甚至是那些不遵循 POSIX 标准的旧 shell。
【解决方案6】:

查看this bash 备忘单,它可以提供很多帮助。

要检查传入参数的长度,请使用"$#"

要使用传入的参数数组,请使用"$@"

检查长度和迭代的示例是:

myFunc() {
  if [[ "$#" -gt 0 ]]; then
    for arg in "$@"; do
      echo $arg
    done
  fi
}

myFunc "$@"

这篇文章对我有帮助,但对我和我的情况来说缺少一些东西。希望这对某人有所帮助。

【讨论】:

  • 谢谢。你是救生员。我的场景是我在脚本中创建了函数,并且脚本接受了一个参数,该参数在脚本中调用的最后一个函数中使用。再次感谢。
【解决方案7】:

这里有一个简单的一行来检查是否只给出了一个参数,否则退出脚本:

[ "$#" -ne 1 ] && echo "USAGE $0 <PARAMETER>" && exit

【讨论】:

    【解决方案8】:

    这里有很多很好的信息,但我想添加一个我觉得有用的简单 sn-p。

    它和上面的有什么不同?

    • 将使用情况打印到 stderr,这比打印到 stdout 更合适
    • 返回这个其他answer中提到的退出代码
    • 无法将其制成单衬...
    _usage(){
        _echoerr "Usage: $0 <args>"
    }
    
    _echoerr(){
        echo "$*" >&2
    }
    
    if [ "$#" -eq 0 ]; then # NOTE: May need to customize this conditional
        _usage
        exit 2
    fi
    main "$@"
    
    

    【讨论】:

      【解决方案9】:

      如果您想安全起见,我建议使用 getopts。

      这是一个小例子:

          while getopts "x:c" opt; do
            case $opt in
              c)
                echo "-$opt was triggered, deploy to ci account" >&2
                DEPLOY_CI_ACCT="true"
                ;;
                  x)
                    echo "-$opt was triggered, Parameter: $OPTARG" >&2 
                    CMD_TO_EXEC=${OPTARG}
                    ;;
                  \?)
                    echo "Invalid option: -$OPTARG" >&2 
                    Usage
                    exit 1
                    ;;
                  :)
                    echo "Option -$OPTARG requires an argument." >&2 
                    Usage
                    exit 1
                    ;;
                esac
              done
      

      在此处查看更多详细信息,例如 http://wiki.bash-hackers.org/howto/getopts_tutorial

      【讨论】:

        【解决方案10】:

        你应该在测试条件之间添加空格:

        if [ $# -ne 1 ]; 
            then echo "illegal number of parameters"
        fi
        

        我希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2015-04-06
          • 2011-05-24
          • 2021-11-18
          • 2012-12-29
          • 1970-01-01
          • 2011-09-09
          • 2011-11-14
          • 2021-08-03
          相关资源
          最近更新 更多