检查bash脚本的任何参数是否与字符串匹配


67

我正在尝试编写一个脚本,在该脚本中,我要检查传递给bash脚本的任何参数是否与字符串匹配。我现在设置的方式是

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

但是可能有很多参数,所以我想知道是否有更好的方法可以做到这一点?

谢谢

编辑:我尝试了这段代码,并使用-disableVenusBld选项调用了脚本,但是它仍然打印出“开始构建”。难道我做错了什么?提前致谢!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi

感谢您的答复,我感谢您抽出宝贵的时间来帮助我。我尝试了一段代码,但似乎无法弄清楚出了什么问题。有任何想法吗?(我已在原始帖子的编辑内容中粘贴了代码)
iman453

嗯:对我有用。我将添加#! /bin/sh -到其中的内容添加到顶部,使脚本可执行,然后显示./t.sh“正在开始构建”,但./t.sh -disableVenusBld不显示任何内容。
诺曼·格雷

Answers:


59

看来您正在外壳程序脚本中执行选项处理。这是成语:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(有几种用于缩进的约定;;,有些shell允许您将选项提供为(--opt1),以帮助进行大括号匹配,但这是基本思想)


3
如果shift事先不知道命令的参数数量(例如,用户可以根据需要提供任意数量的参数),则使用语句。在这种情况下,将在while测试条件为的循环中处理参数$#。只要自变量数量大于零,此条件就成立。该$1变量和shift声明过程的每个参数。每次shift执行时,参数的数量都会减少,最终变为零,然后while退出循环。来源
Serge Stroobandt,2015年

这是带有附加echo $1 | sed参数值处理的类似示例。
Serge Stroobandt,2015年

26

这对我有用。它完全按照您的要求执行操作,仅此而已(无需处理选项)。无论是好的还是坏的,都是发贴人的练习:)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

这利用了$* bash super-test [[]]括号的特殊处理。


2
恕我直言,这必须是最正确的答案,因为问题只需要检查参数的存在即可。但是,我已将更改$*$@,因为要测试的字符串可能有空格,并添加了指向bash文档的链接。
h7r 2015年

9
您是要使用=〜运算符吗?否则,我不明白为什么这应该起作用,并且当我尝试确切的脚本时,实际上它不起作用。
Seppo Enarvi 2015年

3
不工作 bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
托比亚

2
这会将整个参数列表与进行比较your string。我认为您需要执行此答案建议的操作。即:bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foo会工作。
starfry

2
过去四年来,这个答案是错误的,因为h7r的编辑破坏了它。原始答案(我现在已恢复)有效,只要“您的字符串”不包含全局字符且带有一些误报即可。例如,如果命令为,create a new certificate而“您的字符串”为cat,则将报告匹配项,因为certificate 包含 cat
斯科特

8

如何使用通配符搜索整个参数空间:

if [[ $@ == *'-disableVenusBld'* ]]
then

编辑:好的,好的,所以这不是一个流行的答案。怎么样,这太完美了!:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2:好的,好的,也许这不是完美的。。。认为仅当-param在列表的开头并且与-paramXZY或-paramABC匹配时,它才有效。我仍然认为通过bash字符串操作可以很好地解决原始问题,但是我在这里还没有完全解决问题...-可以吗?


您的第二个建议-将过滤替换与完全替换进行比较-效果很好,并且具有不破坏参数列表的优点。
Donal Fellows's

您能否解释第二条建议(尤其是${@#)的含义?
velop

1
@velop当然!因此,您知道这$@是一个包含所有命令行参数的特殊变量吗?好吧,我刚刚在该变量上使用了Bash字符串操作来删除子字符串“ -disableVenusBld”,然后将其与原始字符串进行比较$@。因此,如果$@等于,-foo -bar${@#-disableVenusBld}仍然为-foo -bar,因此我可以看到我要查找的标志不存在。但是,如果$@等于-foo -disableVenusBld -bar然后${@#-disableVenusBld}-foo -bar其不等于$@,这样告诉我,我要找的标志存在!太棒了!
Rich

@velop在此处了解有关Bash字符串操作的更多信息:tldp.org/LDP/abs/html/string-manipulation.html
Rich

@Rich漂亮整洁的^^,谢谢解释。
velop

4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

如果您只需要测试以开头的参数$3,请在函数中进行搜索:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

但是我不知道为什么您首先要尝试这样做,这不是普遍的需求。通常,您会按顺序处理选项,就像丹尼斯对上一个问题的回答一样

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.