【问题标题】:non-POSIX command line parameter parsing using AWK and getopts使用 AWK 和 getopts 解析非 POSIX 命令行参数
【发布时间】:2014-01-11 22:40:33
【问题描述】:

我正在尝试编写一个可以以非 POSIX 方式接受命令行参数的 Bash 脚本。具体来说,我想使用getopts 以标准方式解析命令行参数,同时getopts 及其选项字符串构建一个命令行参数列表unexpected。以我描述的方式进行命令行参数解析的示例显示在下面的代码 cmets 中。我正在寻找解决方案,但我的脚本只能识别 unique 个意外参数,而我需要识别 all 个意外参数。我很感激有关解决此问题的指导(可能通过巧妙的 AWK 脚本编写)。非常感谢您的帮助。

#!/bin/bash
################################################################################
#
# This is a test of command line parameter parsing that is explicitly non-POSIX.
# This approach handles
#     - options (for getopts)
#     - arguments of options (for getopts)
#     - positional arguments (for getopts) and
#     - non-option arguments (command line parameters not expected by getopts).
# All non-option arguments are placed in the string non_option_parameters. The
# silent error reporting mode of getopts is required. Following command line
# parameter parsing, input information can be accepted based on internal
# priority assumptions.
#
# example usage:
#     ./script.sh 
#         non-option parameters:
#     ./script.sh  -a Dirac
#         -a triggered with parameter Dirac
#         non-option parameters: 
#     ./script.sh -a Dirac -b
#         -a triggered with parameter Dirac
#         -b triggered
#         non-option parameters: 
#     ./script.sh -a Dirac Feynman -b
#         -a triggered with parameter Dirac
#         -b triggered
#         non-option parameters: Feynman 
#     ./script.sh -a Dirac Feynman Born -b
#         -a triggered with parameter Dirac
#         -b triggered
#         non-option parameters: Feynman Born 
#     ./script.sh -a Dirac Feynman Born Born -b
#         -a triggered with parameter Dirac
#         -b triggered
#         non-option parameters: Feynman Born 
#
# WANT:
#     ./script.sh -a Dirac Feynman Born Born -b
#         -a triggered with parameter Dirac
#         -b triggered
#         non-option parameters: Feynman Born Born
#
################################################################################

option_string=":a:b"
non_option_parameters=""

process_arguments(){
    OPTIND=1
    while getopts "${option_string}" option; do
        case ${option} in
            a)
                echo "-a triggered with parameter "${OPTARG}"" >&2 # output to STDERR
                ;;
            b)
                echo "-b triggered" >&2 # output to STDERR
                ;;
            \?)
                echo "invalid option: -"${OPTARG}"" >&2 # output to STDERR
            ;;
        esac
    done
    shift $(expr ${OPTIND} - 1)
    echo "$@"
}

parameters="${@}"
while [ ! -z "${parameters}" ]; do
    parameters="$(process_arguments ${parameters})"
    TEMP=$(echo "${parameters}" | awk -F " " '{print $1}')
    IS_POS="$(echo "${option_string}" | sed 's/^:-://' | sed 's/\([a-zA-Z]\)/\ \1/g' | sed 's/\([a-zA-Z]\)/-\1/g' | sed 's/://g' | awk -v OPTION=${TEMP} \
    '{
        for(i=1; i<=NF; i++){
            if( (match($i, OPTION)== 1) && (length($i) == length(OPTION)) ){
            print $i
        }
        }
    }' \
    | wc -l)"
    # The AWK code is quivalent to grep -w "-OPTIONCHAR". Note the trailing '-'
    # character behind OPTIONCHAR). IS_POS tells whether the first element in a
    # space-delimited string of parameters is a positional argument.
    [ ${IS_POS} -eq 0 ] && non_option_parameters="${non_option_parameters} ${TEMP}"
    T_ARRAY=""
    for parameter in ${parameters}; do
        [ $IS_POS -eq 0 ] && [ "${TEMP}" == "${parameter}" ] && continue
        T_ARRAY="${T_ARRAY} ${parameter}"
    done
    parameters="${T_ARRAY}"
done
echo "non-option parameters:${non_option_parameters}"

【问题讨论】:

    标签: parameters awk arguments option getopts


    【解决方案1】:

    我不太明白IS_POS 变量应该做什么。在我的机器( mac )上它总是 0 。第二个“Born”的问题在于T_ARRAY 的构造。当我将其更改为以下内容时:

    T_ARRAY=$(echo "${parameters}" | awk -F " " 'NF > 1 { for( i=2; i<=NF; i++ ) printf("%s%s", $i, i == NF ? "" : " " ); next }')
    

    然后我得到所需的输出:

    % script.sh -a Dirac Feynman Born Born -b
    -a triggered with parameter Dirac
    -b triggered
    non-option parameters: Feynman Born Born
    

    我认为问题出在

    [ $IS_POS -eq 0 ] && [ "${TEMP}" == "${parameter}" ] && continue
    

    for parameter 循环的行匹配太多次。替换 awk 只是从参数中删除了第一个元素 - 显然它没有关注IS_POS。如果在您的系统上IS_POS 不为零,那么您可能需要更改它。

    【讨论】:

    • 非常感谢您在这方面的帮助。那个匹配太多次的循环被很好地发现了。
    【解决方案2】:

    您可以尝试如下简化您的脚本:

    non_option_par=""
    par="${@}"
    while [ ! -z "${par}" ]; do
        par="$(process_arguments ${par})"
        non_option_par="${non_option_par} "$(awk -F'[ \t]*-' '{print $1}' <<<"$par")
        par=$(awk -F'[ \t]*-' 'NF>1{print substr($0,index($0,"-"))}' <<<"$par")
    done
    echo "non-option parameters:${non_option_par}"
    

    (保持process_arguments 函数原样..)

    【讨论】:

    • 非常感谢您在这方面的帮助。你的 AWK 编码比我的好!
    最近更新 更多