如何在 getopts 上使用 ${OPTARG}?

How to use ${OPTARG} on getopts?

我有以下代码:

while getopts ":p:t:n:" o; do
case "${o}" in
    p)
        p=${OPTARG}
        numep=$p
        mkdir $numep
        ;;
    t)
        t=${OPTARG}
        tip=$t
        if [ $tip == "c" ]; then
            touch $numep/$numep.c
            touch $numep/$numep.h
        elif [ $tip == "c++" ]; then
            touch $numep/$numep.cpp
            touch $numep/$numep.h
        fi
            ;;
        n)
            n=${OPTARG}
            nrFis=$n
            if [ $tip == "c" ]; then
                for i in $(seq $n); do
                    touch $numep/src/$numep$i.c
                    touch $numep/inc/$numep$i.h
                done
            elif [ $tip == "c++" ]; then
                for i in $(seq $n); do
                    touch $numep/src/$numep$i.cpp
                    touch $numep/inc/$numep$i.h
                done
            fi
            ;;
        *)
            err-help
            ;;
        esac
    done

err-help 是一个先前定义的函数,它提供正确调用的说明。

脚本的正确调用如下所示:./script.sh -p project_name -t project_type -n source_files_number

我想做什么:为 c 或 c++ 项目创建一个包含特定数量源文件的目录。

我的问题是:我必须如何使用 ${OPTARG} ? p=${OPTARG} 究竟是什么东西? p、t、n 变量会填充正确的内容吗? 请问我怎么做对的? :(

您使用的 getopts 是正确的,但是您假设了您将看到选项的顺序。稍后会详细介绍。

让我们看一下 help getopts

中的几段摘录

OPTSTRING contains the option letters to be recognized; if a letter is followed by a colon, the option is expected to have an argument, which should be separated from it by white space.

... When an option requires an argument, getopts places that argument into the shell variable OPTARG.

这就是getopts 的神奇之处。由于您将 p: 添加到您的 optstring 中,当 $o = "p" 时,变量 $OPTARG 将包含您提供给 -p 的任何内容,在本例中为字符串 "project_name".

现在进行一些代码审查:

case "${o}" in
    p)
        p=${OPTARG}
        numep=$p
        mkdir $numep
        ;;

如果你使用数组,你只需要使用大括号,或者你需要从周围的文本中消除变量名的歧义($o_x vs ${o}_x)这样写会更整洁

case "$o" in ...

您不需要创建与选项同名的特殊变量。你从不使用 $p。你可以只写

numep="$OPTARG"

总是引用你的变量。总是。除非你特别知道什么时候不引用它们。如果我提供 -p "some dir with spaces",那么 mkdir $numep 将创建 4 个目录。你需要写

mkdir "$numep"

如果 $numep 目录已经存在,您将收到一条错误消息。如果您不想那样,请使用 mkdir -p "$numep"(参见 man mkdir

现在,要解决我的第一个问题:调用您的脚本并以任何顺序

提供选项都没有错
./script.sh -t project_type -n source_files_number -p project_name

您的选项解析假定,在 tn 分支中,您已经设置了 $numep,因此您假设用户提供了 -p 第一。如果 -t 先出现,则 $numep 为空,您将尝试创建文件 /.h。即使你有权限写入根目录,这也不是你想要做的。在开始做事之前解析所有你的选择。

我会这样写:

while getopts ":p:t:n:" o; do
    case "$o" in
        p)  numep="$OPTARG" ;;
        t)  case "$OPTARG" in
                c)  ext="c" ;;
                "c++")  ext="cpp" ;;
                *)  echo "Error: use 'c' or 'c++' for -t option" >&2
                    exit 1
                    ;;
            esac
            ;;
        n)  nrFis="$OPTARG" ;;
        *)  err-help ;;
    esac
done

mkdir -p "$numep"
touch "$numep/$numep.$ext"
touch "$numep/$numep.h"
for ((i=1; i<=$nrFis; i++)); do
    touch "$numep/src/$numep$i.$ext"
    touch "$numep/inc/$numep$i.h"
done