在bash中检查命令行标志的正确方法

时间:2010-05-20 15:45:56

标签: bash command-line flags

在脚本中间,我想检查命令行上是否传递了给定的标志。以下是我想要的,但看起来很难看:

if echo $* | grep -e "--flag" -q
then
  echo ">>>> Running with flag"
else
  echo ">>>> Running without flag"
fi

有更好的方法吗?

注意:我明确地想要列出switch / getopt中的所有标志。 (在这种情况下,任何这样的东西都会变成完整脚本的一半或更多。而且if的主体也只是设置了一组变量)

8 个答案:

答案 0 :(得分:53)

您正在做的事情的另一种选择:

if [[ $* == *--flag* ]]

另见BashFAQ/035

  

注意:这也会匹配--flags-off,因为它是一个简单的子字符串检查。

答案 1 :(得分:9)

我通常会在案例陈述中看到这一点。以下是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变量构建其他选项。

答案 2 :(得分:6)

您可以在bash中使用getopt关键字。

来自http://aplawrence.com/Unix/getopts.html

  

getopt的

     

这是一个独立的可执行文件,已经存在很长时间了。   较旧的版本缺乏处理引用参数的能力(foo a“this   将不会工作“c)和那些可以,笨拙地执行的版本。如果你是   运行最近的Linux版本,你的“getopt”可以做到这一点; SCO 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

答案 3 :(得分:1)

我对Eliran Malka的答案做了一些小改动:

此函数可以评估不同的参数同义词,例如“ -q”和“ --quick”。此外,当找到参数时,它不使用return 0/1,而是使用echo来返回非null值:

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

答案 4 :(得分:0)

您可以采用简单的方法,并遍历参数以测试每个参数与给定参数(例如-t)是否相等。

将其放入函数中

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),然后重复使用。封装rulez!
但是即使使用命令,这种力量也会成为缺陷。如果要一次又一次地使用它,则每次都将解析所有参数。

我倾向于支持重用,但是我必须意识到其中的含义。相对的方法是像您所担心的那样在脚本顶部解析一次这些参数,并避免重复解析。
您仍然可以封装该开关盒,它可以随您的决定而大(您不必列出 all 个选项)。

答案 5 :(得分:0)

不是替代方案,而是一种改进。

if echo $* | grep -e "\b--flag\b" -q

寻找word boundaries将确保确实获得选项--flag,而--flagstaff--not-really--flag都不是

答案 6 :(得分:0)

Dennis Williamsonanswer 进行修改,并提供了简短形式参数的附加示例。

if [[ \ $*\  == *\ --flag\ * ]] || [[ \ $*\  == *\ -f\ * ]]

它解决了误报匹配 --flags-off 甚至 --another--flag 的问题(更流行的这种情况是单虚线参数:--one-more-flag for *-f*)。

\ (反斜杠 + 空格)表示 [[ ]] 中表达式的空格。在 $* 周围放置空格可以确保参数既不接触行的开头也不接触行的结尾,它们只接触空格。现在可以在带参数的行中搜索由空格包围的目标标志。

答案 7 :(得分:0)

[!0-9]*[!0-9]