2

我试图理解为什么getopts如果“未命名”参数在任何命名参数之前似乎忽略所有参数。

使用来自http://wiki.bash-hackers.org/howto/getopts_tutorial的示例,

#!/bin/bash

while getopts ":a" opt; do
  case $opt in
    a)
      echo "-a was triggered!" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done

并观察结果:

$ ./opt_test
$ ./opt_test -a
-a was triggered!
$ ./opt_test -a -f
-a was triggered!
Invalid option: -f
$ ./opt_test a -a -f
$ ./opt_test a -a
$ ./opt_test a -f
$ ./opt_test lala -f
$ 

因此,在前面加上一个未命名的参数(一个没有破折号的参数)似乎会getopts忽略所有参数。

为什么会这样,我该如何解决?我希望我的程序能够捕捉到这些东西并打印一个使用屏幕。

4

4 回答 4

3

当程序遇到第一个非选项参数时,停止处理选项是相当标准的行为。这通常正是您想要的。例如,考虑一下:

ssh someremotehost ls -l

如果ssh尝试在第一个非选项参数之后处理选项,您将永远无法将参数传递给远程命令。getopt 支持的另一个标准是选项处理在--参数处显式停止,因此您可以执行以下操作来删除名为 的文件-f

rm -- -f

如果您真的想在命令行的任何位置处理选项,您可以编写自己的选项处理例程。这并不是真的那么困难,您也可以实现对长选项 ( --this-is-a-long-option) 的支持。

于 2011-11-18T14:49:51.580 回答
2

我使用的一种解决方法是将数组切片传递给 getopts:

而不是这个:

while getopts ":a" opt; do

尝试这个:

while getopts ":a" opt ${@:2}; do

这会将第二个到最后一个参数传递给 getopts 以进行解析,并且可以正常工作以忽略第一个参数。

于 2014-02-24T17:27:32.957 回答
1

引用getopts 文档

“以下任何一项都应标识选项的结尾:特殊选项“--”,找到不以 '-' 开头的参数,或遇到错误。”

于 2011-11-18T14:53:42.463 回答
0

要让选项出现在未命名(位置)参数之前,请使用shift后记来清理,

例如有一个没有值的选项:

while getopts "u" opt; do
case $opt in
  u) USE_USERNAMES="TRUE"
  ;;
  \?) echo "Invalid option -$OPTARG" >&2
  ;;
esac
done

# Clean-up after arguments parsing
if test "$USE_USERNAMES"; then
  shift 
fi

或者,有一个值:

while getopts "s:" OPT; do
case $OPT in
  s) SUBMISSIONS="$OPTARG"
  ;;
  \?) echo "Invalid option -$OPTARG" >&2
      exit 1
  ;;
esac
done

# Clean-up arguments and assign default values AFTER arguments parsing
if test "$SUBMISSIONS"; then
  shift 2
else
  SUBMISSIONS="./logins.txt"
fi

# Move on to unnamed (positional) arguments
if ! test "$1"; then
  echo "ERROR: Required first argument missing"
  exit 1
fi

# Use arguments
echo "SUBMISSIONS: $SUBMISSIONS"
echo "FIRST ARG: $1"

参考

于 2015-03-02T17:02:12.357 回答