【问题标题】:Using getopts inside a Bash function在 Bash 函数中使用 getopts
【发布时间】:2013-05-15 07:28:24
【问题描述】:

我想在我在 .bash_profile 中定义的函数中使用getopts。 这个想法是我想将一些标志传递给这个函数来改变它的行为。

代码如下:

function t() {
    echo $*
    getopts "a:" OPTION
    echo $OPTION
    echo $OPTARG
}

当我这样调用它时:

t -a bc

我得到这个输出:

-a bc
?
 

怎么了?我想在不手动移动和解析的情况下获得值bc。如何在函数中正确使用getopts

编辑:更正我的代码 sn-p 以尝试 $OPTARG,但无济于事

编辑#2:好的结果证明代码很好,我的外壳不知何故搞砸了。打开一个新窗口解决了它。 arg 值确实在 $OPTARG 中。

【问题讨论】:

    标签: bash function getopts


    【解决方案1】:

    参数存储在变量$OPTARG中。

    function t() {
      echo $*
      getopts "a:" OPTION
      echo $OPTION
      echo $OPTARG
    }
    

    输出:

    $ t -a bc
    -a bc
    a
    bc

    【讨论】:

    • 对不起,我错误地粘贴了我的代码 sn-p... 我也回显了 $OPTARG,这是第三行,它是空白的。还有其他想法吗?
    • @Magnus 可能是因为您多次调用该函数并且 $OPTIND 未在本地定义(请参阅 Adrian 的回答)。虽然我很感激你接受了我的回答,但你或许更应该接受他的回答。
    • 该代码仅在粘贴到 shell 时有效,在脚本中无效。
    • @kenorb 从脚本中可以正常工作。这不是我编的。
    • 好的,我不确定t 是如何被调用的,我必须在脚本中调用t -a bc 或添加t "$@",最初我认为它可以不使用。跨度>
    【解决方案2】:

    正如@Ansgar 指出的那样,您选项的参数存储在${OPTARG} 中,但这并不是在函数中使用getopts 时唯一需要注意的事情。您还需要通过取消设置或声明local 来确保${OPTIND} 是函数的本地函数,否则在多次调用函数时会遇到意外行为。

    t.sh:

    #!/bin/bash
    
    foo()
    {
        foo_usage() { echo "foo: [-a <arg>]" 1>&2; exit; }
    
        local OPTIND o a
        while getopts ":a:" o; do
            case "${o}" in
                a)
                    a="${OPTARG}"
                    ;;
                *)
                    foo_usage
                    ;;
            esac
        done
        shift $((OPTIND-1))
    
        echo "a: [${a}], non-option arguments: $*"
    }
    
    foo
    foo -a bc bar quux
    foo -x
    

    示例运行:

    $ ./t.sh
    a: [], non-option arguments:
    a: [bc], non-option arguments: bar quux
    foo: [-a <arg>]
    

    如果你注释掉# local OPTIND,你会得到这样的结果:

    $ ./t.sh
    a: [], non-option arguments:
    a: [bc], non-option arguments: bar quux
    a: [bc], non-option arguments:
    

    除此之外,其用法与在函数外使用时相同。

    【讨论】:

    • 1.) 1&gt;&amp;2 中的 1 不是必需的。 2.) 您没有将aoOPTARG 定义为本地。 3.) exit 不会退出脚本,而只是一个子shell。为了退出脚本,必须在外壳中输入set -e,在子shell 中输入exit 1。该示例不会触发问题,但 MSG=$(foo ...) 会触发。
    • @ceving 1) 这是编码风格的问题,但是,不,根据语言定义,这不是必需的。 2)同意,那些应该是本地的。 3)正如你所说,exit 退出我的示例中的脚本。当然exit 不会退出子shell,但这不是这个问题的具体问题。您不必使用set -e,您只需要确保捕获错误并且MSG=$(foo ...) || die 也可以正常工作。 set -ebut it's not idiot-proof 问题的一种解决方案,我和其他许多人一样,不建议使用它。
    • 只是指出,即使您没有在函数中使用 OPTIND(例如,使用 shift;),它仍然需要本地化才能具有可预测的行为。
    • @ceving,你可以看这里,stackoverflow.com/questions/61566331/… - 我添加了local,但没有帮助
    【解决方案3】:

    下面是 getopts 在 shell 函数中使用的简单示例:

    #!/usr/bin/env bash
    t() {
      local OPTIND
      getopts "a:" OPTION
      echo Input: $*, OPTION: $OPTION, OPTARG: $OPTARG
    }
    t "$@"
    t -a foo
    

    输出:

    $ ./test.sh -a bc
    Input: -a bc, OPTION: a, OPTARG: bc
    Input: -a foo, OPTION: a, OPTARG: foo
    

    作为@Adrian pointed out,需要设置local OPTIND(或OPTIND=1),因为shell不会在multiple calls to getoptsman bash)之间自动重置OPTIND

    getopts 的基本语法是:

    getopts OPTSTRING VARNAME [ARGS...]
    

    默认情况下,不指定参数等效于使用“$@”显式调用它,即:getopts "a:" opts "$@"

    如果出现问题,这些是getopts用来检查的变量:

    • OPTIND - 要处理的下一个参数的索引,
    • OPTARG - 变量设置为getopts 找到的选项的任何参数,
    • OPTERR(不是 POSIX)- 设置为 0 或 1 以指示 Bash 是否应显示由 getopts 生成的错误消息。

    更多信息,请参阅:The Bash Hackers Wiki 上的 Small getopts tutorial

    【讨论】:

    猜你喜欢
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 2013-05-05
    相关资源
    最近更新 更多