关于shell:bash参数解析逻辑进入无限循环

Bash arguments parse logic runs into infinite loop

本问题已经有最佳答案,请猛点这里访问。

我有一个循环来解析命令行参数。如果-d或-b参数有一个参数,一切都可以正常工作。但是当我传递没有参数的-d或-b时,脚本进入无限循环。

1
2
3
4
5
6
7
8
# Parse command line input
while ["$#" -gt 0 ]; do
  case"$1" in
    -d) DOMAIN="$2"; shift 2;;
    -b) BITS="$2"; shift 2;;
     *) die"unrecognized argument: $1"
  esac
done

如何在空参数上引发错误?


如果您试图移动的值超过列表中的值数,那么shift n命令将不起任何作用。这就是代码中出现无限循环的原因。

使用getopts是正确的,因为它给了您很大的灵活性。否则,可以这样重写循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# Parse command line input
d_flag=0
b_flag=0
while ["$#" -gt 0 ]; do
  case"$1" in
    -d)
        d_flag=1
        shift
        [[ $1 == -* ]] && continue # argument to -d not given
        DOMAIN=$1
        shift
        ;;
    -b)
        b_flag=1
        shift
        [[ $1 == -* ]] && continue # argument to -b not given
        BITS=$1
        shift
        ;;
     *) echo"unrecognized argument: $1"; exit 2;;
  esac
done

if [[ $d_flag = 1 && -z $DOMAIN ]]; then
    # handle error - option requires an argument
fi

if [[ $b_flag = 1 && -z $BITS ]]; then
    # handle error - option requires an argument
fi

由于参数不足,移位失败。

但是,这个问题很明显,因为您将shell设置为在所有错误上都失败(使用set -e)。在许多情况下,它通过避免静默的失败使调试变得更加容易,并强制执行规范和错误检查。set -u在变量扩展失败时会导致错误,也非常有用。


由于您似乎总是需要两个参数,因此可以将第一行更改为:

1
while ["$#" -eq 2 ]; do

否则,您可以在进入循环之前检查$2的值,如下所示:

1
2
3
4
5
if [[ -z $2 ]]; then
echo"missing second parameter"
else
#do the while loop
fi