在脚本中间,我想检查给定的标志是否在命令行上传递。以下是我想要的,但看起来很难看:
if echo $* | grep -e "--flag" -q
then
echo ">>>> Running with flag"
else
echo ">>>> Running without flag"
fi
还有更好的方法吗?
注意:我明确地不想 列出开关/getopt 中的所有标志。 (在这种情况下,任何这样的东西都会成为完整脚本的一半或更多。还有 if 的主体只是设置了一组变量)
我通常看到这是通过案例陈述完成的。这是 git-repack 脚本的摘录:
while test $# != 0
do
case "$1" in
-n) no_update_info=t ;;
-a) all_into_one=t ;;
-A) all_into_one=t
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) GIT_QUIET=t ;;
-f) no_reuse=--no-reuse-object ;;
-l) local=--local ;;
--max-pack-size|--window|--window-memory|--depth)
extra="$extra $1=$2"; shift ;;
--) shift; break;;
*) usage ;;
esac
shift
done
请注意,这允许您检查短标志和长标志。在这种情况下,其他选项是使用
extra
变量建立的。
您可以采用直接的方法,并迭代参数以测试每个参数是否与给定参数相等(例如
-t
,--therizinosaurus
)。
将其放入函数中:
has_param() {
local term="$1"
shift
for arg; do
if [[ $arg == "$term" ]]; then
return 0
fi
done
return 1
}
… 并将其用作测试表达式中的谓词:
if has_param '-t' "$@"; then
echo "yay!"
fi
if ! has_param '-t' "$1" "$2" "$wat"; then
echo "nay..."
fi
如果你想拒绝空参数,在循环体的顶部添加一个退出点:
for arg; do
if [[ -z "$arg" ]]; then
return 2
fi
# ...
这非常可读,并且不会像模式匹配或正则表达式匹配那样给你误报。
它还允许在任意位置放置标志,例如,您可以将
-h
放在命令行的末尾(不考虑它是好是坏)。
但是越想越觉得烦
有了函数,您可以采用任何实现(例如
getopts
),并重用它。封装规则!我倾向于重用,但我必须意识到其中的含义。相反的方法是在脚本顶部解析这些参数一次,就像你害怕的那样,并避免重复解析。
你仍然可以封装那个开关盒,它可以和你决定的一样大(你不必列出all选项)。
您可以在 bash 中使用 getopt 关键字。
来自http://alawrence.com/Unix/getopts.html:
getopt
这是一个独立的可执行文件,已经存在了很长时间。 旧版本缺乏处理引用参数的能力(foo a "this 不会工作” c) 和可以的版本,笨拙地这样做。如果你是 运行最新的 Linux 版本,您的“getopt”可以做到这一点;上合OSR5, Mac OS X 10.2.6 和 FreeBSD 4.4 有一个旧版本没有。
“getopt”的简单用法在这个迷你脚本中展示:
#!/bin/bash
echo "Before getopt"
for i
do
echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
echo "-->$i"
done
我对Eliran Malka的答案做了一些小改动:
这个函数可以评估不同的参数同义词,比如“-q”和“--quick”。此外,它不使用 return 0/1 而是使用 echo 在找到参数时返回非空值:
function has_param() {
local terms="$1"
shift
for term in $terms; do
for arg; do
if [[ $arg == "$term" ]]; then
echo "yes"
fi
done
done
}
# Same usage:
# Assign result to a variable.
FLAG_QUICK=$(has_param "-q --quick" "$@") # "yes" or ""
# Test in a condition using the nonzero-length-test to detect "yes" response.
if [[ -n $(has_param "-h --help" "$@") ]]; then;
echo "Need help?"
fi
# Check, is a flag is NOT set by using the zero-length test.
if [[ -z $(has_param "-f --flag" "$@") ]]; then
echo "FLAG NOT SET"
fi
if [ "$1" == "-n" ]; then
echo "Flag set";
fi
Dennis Williamson的answer的修改与简短形式的论证的附加示例。
if [[ \ $*\ == *\ --flag\ * ]] || [[ \ $*\ == *\ -f\ * ]]
它解决了误报匹配
--flags-off
甚至--another--flag
的问题(对于单破折号参数更流行的这种情况:--one-more-flag
for *-f*
)。
\
(反斜杠+空格)表示[[ ]]
内的表达式空间。在 $*
周围放置空格可以确保参数既不接触行的开头也不接触行的结尾,它们只接触空格。现在可以在带参数的行中搜索被空格包围的目标标志。
这是投票最多的答案的变体,不会发现误报
if [[ " $* " == *" -r "* ]]; then
不是替代品,而是改进。
if echo $* | grep -e "\b--flag\b" -q
寻找 word boundaries 将确保真正获得选项
--flag
而既不是 --flagstaff
也不是 --not-really--flag
另一个变化:
flag1="false"
if [[ " $@ " =~ " --flag1 " ]]; then
flag1="true"
fi
flag2="false"
if [[ " $@ " =~ " --flag2 " ]]; then
flag2="true"
fi
Mb 像这样的东西:
if [[ ($* == -f) || ($* == --flag) ]];
then
echo ">>>> Running with flag"
else
echo ">>>> Running without flag"
fi