捕获 getopt 无效选项

发布于 2024-12-08 13:58:18 字数 1249 浏览 4 评论 0原文

我使用 getopt (不是 getops)为我的 bash 脚本提供处理选项和开关(长 --option 和短 -o 形式)的能力。

我希望能够捕获无效选项并处理它们,通常会回显用户应该尝试 cmd --help ,然后退出脚本。

问题是,无效选项被 getopt 捕获,它本身输出一条消息,例如“getopt:无效选项 -- 'x'”

这是我用来设置 getopt 参数的模式:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@")

其中 $LONG_OPTIONS 和 $ SHORT_OPTIONS 是逗号分隔的选项列表。

以下是我处理选项的方式:

 while [ $# -gt 0 ]
    do
        case "$1" in
            -h|--help)
                cat <<END_HELP_OUTPUT

    Help
    ----

    Usage: ./cmd.sh 

    END_HELP_OUTPUT

                shift;
                exit
                ;;
            --opt1)
                FLAG1=true
                shift
                ;;
            --opt2)
                FLAG2=true
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Option $1 is not a valid option."
                echo "Try './cmd.sh --help for more information."
                shift
                exit
                ;;
        esac
    done

getopt -q 将抑制输出,但 case 语句中的捕获方案仍然无法达到我的预期。相反,尽管参数无效,程序仍然会执行。

I'm using getopt (not getops) to provide the ability for my bash script to process options and switches (both long --option and short -o forms).

I'd like to be able to trap invalid options and handle them, typically echoing out that the user should try cmd --help and then exiting the script.

Thing is, the invalid options are being caught by getopt, which is itself outputting a message such as "getopt: invalid option -- 'x'"

Here's the pattern I'm using to set my getopt parameters:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@")

where both $LONG_OPTIONS and $SHORT_OPTIONS are a comma-delimited list of options.

Here's how I handle processing the options:

 while [ $# -gt 0 ]
    do
        case "$1" in
            -h|--help)
                cat <<END_HELP_OUTPUT

    Help
    ----

    Usage: ./cmd.sh 

    END_HELP_OUTPUT

                shift;
                exit
                ;;
            --opt1)
                FLAG1=true
                shift
                ;;
            --opt2)
                FLAG2=true
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Option $1 is not a valid option."
                echo "Try './cmd.sh --help for more information."
                shift
                exit
                ;;
        esac
    done

getopt -q will suppress the output, but my trapping scheme within the case statement still fails to do what I expect. Instead, the program just executes, despite the invalid arguments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

肩上的翅膀 2024-12-15 13:58:18

这种风格适合我:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "$@")"

if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$params"
unset params

while true
do
    case $1 in
        -d|--diff)
            diff_exec=(${2-})
            shift 2
            ;;
        -h|--help)
            usage
            exit
            ;;
        --)
            shift
            break
            ;;
        *)
            usage
            ;;
    esac
done

This sort of style works for me:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "$@")"

if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$params"
unset params

while true
do
    case $1 in
        -d|--diff)
            diff_exec=(${2-})
            shift 2
            ;;
        -h|--help)
            usage
            exit
            ;;
        --)
            shift
            break
            ;;
        *)
            usage
            ;;
    esac
done
沧桑㈠ 2024-12-15 13:58:18

这不是最稳健的解决方案,但它是合理的;它依赖于以下内容:

  • getopt 打印的错误消息以“getopt:”为前缀
  • 假设可以接受通过 getopt 的清理版本'错误消息,并添加了自定义信息。

代码片段:

# Invoke getopt; suppress its stderr initially.
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>/dev/null)
if [[ $? -ne 0 ]]; then # getopt reported failure
    # Rerun the same getopt command so we can capture stderr output *only* this time.
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input.
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here.
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>&1 1>&-)
    # Strip getopt's prefix and augment with custom information.
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2
    exit 1
fi

This is not the most robust solution, but it's reasonable; it relies on the following:

  • The error message that getopt prints is prefixed with "getopt: "
  • The assumption is that it's acceptable to pass through a cleaned-up version of getopt's error message, augmented with custom information.

Code snippet:

# Invoke getopt; suppress its stderr initially.
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>/dev/null)
if [[ $? -ne 0 ]]; then # getopt reported failure
    # Rerun the same getopt command so we can capture stderr output *only* this time.
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input.
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here.
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>&1 1>&-)
    # Strip getopt's prefix and augment with custom information.
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2
    exit 1
fi
逆光飞翔i 2024-12-15 13:58:18

您必须使用 getopt 吗?如果您只是使用

while [ $# -gt 0 ]; do
  case "$1" in
    -d|--diff)
       diff_exec=(${2-})
       shift
       ;;
    -h|--help)
       usage
       exit
       ;;
     --)
       break
       ;;
     *)
       usage
       ;;
    esac
    shift
done

那么您自己的代码正在执行检查。

Do you have to use getopt at all? If you just use

while [ $# -gt 0 ]; do
  case "$1" in
    -d|--diff)
       diff_exec=(${2-})
       shift
       ;;
    -h|--help)
       usage
       exit
       ;;
     --)
       break
       ;;
     *)
       usage
       ;;
    esac
    shift
done

Then you own code is doing the checking.

糖果控 2024-12-15 13:58:18

我发现它可以作为 getopts case 语句中的最后一项:

*) eval echo "Unrecognized arg \$$[OPTIND-1]";用法;出口 ;;

I found this to work as the last item in the getopts case statement:

*) eval echo "Unrecognized arg \$$[OPTIND-1]"; usage; exit ;;

红衣飘飘貌似仙 2024-12-15 13:58:18

我不确定这是否有帮助,但是 getopt(1) 使用 getopt(3) 并且如果我没记错的话 getopt(3)如果 OPTSTRING 的第一个字符是冒号,则抑制错误报告。

I'm not sure if this can help, but getopt(1) uses getopt(3) and if I recall correctly getopt(3) suppress error reporting if the fist character of the OPTSTRING is a colon.

不疑不惑不回忆 2024-12-15 13:58:18

这是我使用过的命令行解析。可以通过更多解析逻辑来改进它来处理丢失的选项和参数。

对于命令行:-a AA -b BB -c CC,结果 s/ba=AA b=BB c=CC

OPT=( "$@" )  # Parses the command line into words.

for [[ I=0;I<${#OPT[@]};I++ ]]  
   do
      case "${OPT[$I]}" in         
         -a) a=${OPT[$I+1]} ;;         
         -b) b=${OPT[$I+1]} ;;         
         -c) c=${OPT[$I+1]} ;;    
      esac
  done

Here is a command line parsing I have used. It could be improved with more parsing logic to handle missing options and parameters.

For the command line: -a AA -b BB -c CC, the result s/b a=AA b=BB c=CC

OPT=( "$@" )  # Parses the command line into words.

for [[ I=0;I<${#OPT[@]};I++ ]]  
   do
      case "${OPT[$I]}" in         
         -a) a=${OPT[$I+1]} ;;         
         -b) b=${OPT[$I+1]} ;;         
         -c) c=${OPT[$I+1]} ;;    
      esac
  done
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文