在Bash中处理具有多个参数的命令行选项

时间:2017-09-24 21:02:55

标签: bash command-line-arguments

我一直在研究使用bash脚本处理命令行参数。我有多个可选参数,每个参数都有一个或多个操作数。一个例子是:

./script.sh -f file1 file2 -s server1 server2

-f本身是可选的,但必须后跟文件名; -s是可选的,可以在没有任何操作数或操作数的情况下使用。

我知道我可以强制将“”放在操作数上,所以我只处理带有一个操作数的参数,并且可以使用case $1 $2 shfit来处理它。

但是我有兴趣这样做没有引号,只是为了为用户节省一些打字。

粗略的想法将在"$@"中作为一个字符串读取,并按空格分隔,然后使用-/--定位参数并在其后面分配操作数。也许我可以使用数组来做到这一点?

欢迎任何建议。

1 个答案:

答案 0 :(得分:1)

感谢大家提出的精彩建议。花了一些时间后,我决定采用下面的解决方案:

简单地说,我使用case和几个检查来确定参数是否是一个选项。我在参数处理期间只使用alter flag变量,然后使用flags来确定我将执行的函数。在某种程度上,我可以选择不同的顺序。

  

的main(){
        #flags,1为false,0为true。该死的bash LOCAL_DEPLOY = 1         SERVER_DEPLOY = 1 DRY_RUN = 0

FILES=("${ALLOWEDFILES[@]}"); 
DEPLOYTARGET=("${ALLOWEDSERVERS[@]}"); 

if [ $# -eq 0 ]
then
    printf -- "Missing optins, perform DRY RUN\nFor help, run with -h/--help\n"
    for target in "${FILES[@]}"; do generate "$target"; done
    echo "....dry run: markdown files generated in rendered/"
    exit 0
fi  

while true ; do
    case "$1" in 
        -f |--file) # required operands
            case "$2" in
                "") die $1 ;;
                *) 
                    FILES=($2)
                    for i in "${FILES[@]}"; do
                        if  is_option $i; then die $1; fi # check for option 
                                                    if ! check_allowed $i ${ALLOWEDFILES[@]}; then exit 1; fi
                    done; 
                    shift 2;; # input FILES are good
            esac ;;
        -l|--local) # no operands expected
            DRY_RUN=1 # turn off dryrun
            LOCAL_DEPLOY=0 # turn on local deploy
            shift ;;
        -s|--server) # optional operands
            case "$2" in
                "") shift ;; 
                *) 
                    DEPLOYTARGET=($2)  # use input
                    for i in "${DEPLOYTARGET[@]}"; do
                        if  is_option $i; then die $1; fi # check for option 
                                                    if ! check_allowed $i ${ALLOWEDSERVERS[@]}; then exit 1; fi
                    done ; shift 2;; # use input value
            esac
            DRY_RUN=1
            SERVER_DEPLOY=0
            ;;
        -n|--dryrun) # dry-run:generate markdown files only
            DRY_RUN=0
            shift ;;
        -h|--help) # docs
            print_help
            exit 0
            ;;
        --) shift; break ;;
        -?*)
            printf 'ERROR: Unkown option: %s\nExisting\n\n' "$1" >&2
            print_help
            exit 1
            shift
            ;; 
        *) 
            break ;; 
    esac 
done

echo  "choose files: ${FILES[@]}"
echo ""

# dry-run
if [ $DRY_RUN == 0 ]; then
    echo "..perform dry run.."
    for target in "${FILES[@]}"; do generate "$target"; done
    echo "....dry run: markdown files generated in rendered/"
    exit 0
fi

# local-deploy
if [ $LOCAL_DEPLOY == 0 ] && [ $SERVER_DEPLOY != 0 ]; then
    echo "..deploy locally"
    for target in "${FILES[@]}"; do 
        generate "$target" > /dev/null
        deploylocal "$target"
    done; 

    # sync hexo-gcs hexo-yby
    cd "$(dirname $HEXOLOCATION)"
    ./syncRepo.sh
    printf -- "....hexo-gcs hexo-yby synced\n"
    cd $CURRENTLOCATION
fi

# server-deploy
if [ $SERVER_DEPLOY == 0 ]; then
    echo "..deploy on servers: ${DEPLOYTARGET[@]}"
    echo ""

    for target in "${FILES[@]}"; do # deploy locally 
        generate "$target" > /dev/null
        deploylocal "$target"
    done 

    # sync hexo-gcs hexo-yby
    cd "$(dirname $HEXOLOCATION)"
    ./syncRepo.sh
    printf -- "....hexo-gcs hexo-yby synced\n"
    cd $CURRENTLOCATION

    # deploy to selected server: git or gcp
    for dt in "${DEPLOYTARGET[@]}"; do 
        deployserver $dt 
    done
fi

}