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 变量会填充正确的内容吗?请问我怎么做才对?:(
您使用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)
您的选项解析假设,在t和n分支中,您已经设置了 $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)