如何在 bash 中结合 getopts 和位置参数?

bnt*_*zio 4 parameters bash shell getopts

我想同时使用getopts和位置参数,但是如果我将位置参数传递给程序,则会getopts丢失。

directory=$1

while getopts l: flag; do
  case "$flag" in
    l) level=$OPTARG;;
  esac
done

if [ -n "$level" ]; then
  echo "Level exist!"
else
  echo "Level doesn't exist!"
fi
Run Code Online (Sandbox Code Playgroud)

所以当我像这样运行程序时:

sh myprogram.sh ~/documents -l 2
Run Code Online (Sandbox Code Playgroud)

我预计:

Level exist!

相反,它返回:

Level doesn't exist!

问题是,如果我在没有位置参数(~/documents)的情况下运行程序,如下所示:

sh myprogram.sh -l 2

我得到正确的输出:

Level exist!

这是为什么?如何getopts在 bash 中同时使用位置参数?

谢谢!

gle*_*man 10

大多数工具都以以下形式编写: tool [options] arg ...

所以你会这样做:

# first, parse the options:
while getopts l: flag; do
  case "$flag" in
    l) level=$OPTARG;;
    \?) exit 42;;
  esac
done

# and shift them away
shift $((OPTIND - 1))

# validation
if [ -n "$level" ]; then
  echo "Level exist!"
else
  echo "Level doesn't exist!"
fi

# THEN, access the positional params
echo "there are $# positional params remaining"
for ((i=1; i<=$#; i++)); do
  printf "%d\t%s\n" $i "${!i}"
done
Run Code Online (Sandbox Code Playgroud)

使用 \?如果用户提供未知选项或未能提供必需参数,则中止脚本

并像这样调用它:

# first, parse the options:
while getopts l: flag; do
  case "$flag" in
    l) level=$OPTARG;;
    \?) exit 42;;
  esac
done

# and shift them away
shift $((OPTIND - 1))

# validation
if [ -n "$level" ]; then
  echo "Level exist!"
else
  echo "Level doesn't exist!"
fi

# THEN, access the positional params
echo "there are $# positional params remaining"
for ((i=1; i<=$#; i++)); do
  printf "%d\t%s\n" $i "${!i}"
done
Run Code Online (Sandbox Code Playgroud)

但是您不能将选项放在参数之后:getopts 在找到第一个非选项参数时停止

$ bash test.sh
Level doesn't exist!
there are 0 positional params remaining

$ bash test.sh -l 2
Level exist!
there are 0 positional params remaining

$ bash test.sh -l 2 foo bar
Level exist!
there are 2 positional params remaining
1   foo
2   bar

$ bash test.sh -x
test.sh: illegal option -- x

$ bash test.sh -l
test.sh: option requires an argument -- l
Run Code Online (Sandbox Code Playgroud)