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

Mar*_*rko 3 linux bash 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

gle*_*man 6

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

让我们看看其中的一些摘录 help getopts

OPTSTRING 包含要识别的选项字母;如果一个字母后跟一个冒号,则该选项应该有一个参数,它应该与它用空格分隔。

... 当一个选项需要一个参数时, getopts 将该参数放入 shell 变量 OPTARG 中

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

现在进行一些代码审查:

case "${o}" in
    p)
        p=${OPTARG}
        numep=$p
        mkdir $numep
        ;;
Run Code Online (Sandbox Code Playgroud)

如果您使用数组,则只需要使用大括号,或者您需要从周围的文本中消除变量名称的歧义($o_xvs ${o}_x)写起来会更整洁

case "$o" in ...
Run Code Online (Sandbox Code Playgroud)

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

numep="$OPTARG"
Run Code Online (Sandbox Code Playgroud)

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

mkdir "$numep"
Run Code Online (Sandbox Code Playgroud)

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

现在,请解决我的第一个问题:调用脚本并以任何顺序提供选项都没有错

./script.sh -t project_type -n source_files_number -p project_name
Run Code Online (Sandbox Code Playgroud)

您的选项解析假设,在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
Run Code Online (Sandbox Code Playgroud)