2014-01-11 40 views
1

我正在尝试编写一个Bash脚本,该脚本可以接受非POSIX方式的命令行参数。具体来说,我想用标准方式解析命令行参数,使用getopts,而也是建立命令行参数列表意外getopts及其选项字符串。下面的代码注释中显示了以我描述的方式解析示例命令行参数。我接近的解决方案,但我的脚本只能识别独特的意外的参数,而我需要识别所有意外的参数。我希望能够解决这个问题的指导(可能通过聪明的AWK脚本)。非常感谢您的帮助。使用AWK和getopts解析非POSIX命令行参数

#!/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 "[email protected]" 
} 

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}" 

回答

1

你可以尽量简化你的脚本如下:

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功能,因为它是..)

+0

非常感谢您的帮助。你的AWK编码比我的更好! – d3pd

2

我不太明白IS_POS变量应该做什么。我的机器上一直是0(mac)。第二个“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非零,那么你可能需要改变它。

+0

非常感谢你对你的帮助。该匹配次数过多的循环很好被发现。 – d3pd