在函数中调用的getopts没有拾取标记

时间:2013-09-09 19:12:38

标签: bash getopts

我从.bash_profile调用以下脚本:

# Set directories based on current path
__set_dirs() {
    currdir=`pwd`
    if [[ ${currdir} =~ "\/path\/to\/main\/(.*)\/working\/([a-z]+)(/?.*)" ]]
    then
        ws=${BASH_REMATCH[1]}
        subdirs=${BASH_REMATCH[3]}
        stgdir=${ts}/${ws}/STAGING${subdirs}
    else
        echo "${currdir} is not a workspace"
        stgdir=""
    fi
}

# Update local version with staging version
upd() {
    __set_dirs
    if [[ -n ${stgdir} ]]
    then
        __overwrite=0
        while getopts "o" opt
        do
            case $opt in
                o)
                    __overwrite=1
                    ;;
                \?)
                    echo "Invalid option: -$OPTARG" >&2
                    ;;
            esac
        done

        echo "Updating ${currdir} with latest from ${stgdir}..."
        if [ ${__overwrite} -eq 0 ]
        then
            update -r ${stgdir} ${currdir}
        else
            echo "Overwriting all local changes!"
            update -r -w ${stgdir} ${currdir}
        fi
    fi
    unset __overwrite
}

执行时

> upd -o

该标志被完全忽略 - 我从未看到“覆盖所有本地更改!”消息。我在某个地方错过了什么吗?

更新: 工作,但只有第一次时间我运行脚本。从第二次开始,该标志被忽略。

2 个答案:

答案 0 :(得分:4)

好吧,想通了:

在搜索man page for getopts之后,我发现了这个花絮(强调我的):

  

每次调用它时,getopts都会放置......下一个参数的索引   处理成变量OPTIND。 OPTIND初始化为1   调用shell或shell脚本的时间.... shell不会   自动重置OPTIND;它必须在两者之间手动重置   如果要使用一组新参数,则在同一个shell调用中多次调用getopts。

由于我只使用.bashrc运行一次脚本,OPTIND只会初始化一次。我第一次运行这个功能,一切都是笨拙的。第二次打开时,OPTIND设置为2,而getopts找不到任何内容,因此会继续。

有了这些知识,我修改了upd()以将OPTIND重置为1:

upd() {
    __set_dirs
    if [[ -n ${stgdir} ]]
    then
         __overwrite=0
         OPTIND=1
         while getopts "o" opt
...

修复了它。 OPTIND:比你想象的更重要。

答案 1 :(得分:2)

getopts对传递给函数的参数起作用,因此在您的情况下,您必须使用upd()调用"$@"函数,以将所有命令行参数传递到函数中。

例如:

test() {
  while getopts "o" opt; do
    case $opt in
    o)
      echo o
    ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
    ;;
    esac
  done
}
test # this wont work as $1, $2, ... are not set
test $@ # this will work as you pass along the command line parameters

修改

我忽略了.bashrc部分,如果我将上面的示例提供给我的运行shell,那么test -o就会按预期工作。