在bash中,如何确定一组变量中只有一个具有值?

时间:2019-02-22 15:47:05

标签: bash

我有三个变量,我们将它们称为DATEURIURI_FILE。它们包含使用getopt处理命令行的结果:

while getopts ":d:p:u:hFA" opt; do

   case $opt in
       d) DATE=$OPTARG;;
       u) URI=${OPTARG};;
       U) URI_FILE=${OPTARG};;
       F) FORCE=yes;;
       A) ALL=yes;;

   esac

done

如果将多个变量中的一个以上设置为任意值(它们是备用命令行选项),我将失败并出错。我对如何进行优雅测试一无所知。我有类似的东西:

#!/bin/bash 

if [[ -z "${URI+x}" ]]
then
    URI_PRESENT=0
else
    URI_PRESENT=1
fi

if [[ -z "${URI_FILE+x}" ]]
then
    URI_FILE_PRESENT=0
else
    URI_FILE_PRESENT=1
fi

if [[ -z "${DATE+x}" ]]
then
    DATE_PRESENT=0
else
    DATE_PRESENT=1
fi


ARGCOUNT=$((${DATE_PRESENT} + ${URI_FILE_PRESENT} + ${URI_PRESENT}))

if (( ${ARGCOUNT} > 1 ))
then
    echo "Only one of date, uri and uri-file may be supplied"
    exit 1
fi

必须有一种更清洁的方法来执行此操作。有什么建议吗?我将至少添加更多替代方案,这会很痛苦

3 个答案:

答案 0 :(得分:3)

counter=0
[[ $DATE ]] && ((counter+=1))
[[ $URI ]] && ((counter+=1))
[[ $URI_FILE ]] && ((counter+=1))

if ((counter > 1))
then
    echo "Only one of date, uri and uri-file may be supplied" >&2
    exit 1
fi

答案 1 :(得分:3)

来自mickp's comment

  

为什么没有一个标志会在每个case表达式中递增,然后测试它是否大于1?

已实施:

while getopts ":d:p:u:hFA" opt; do
   case $opt in
   d) DATE=$OPTARG
      ((count++));;
   u) URI=${OPTARG}
      ((count++));;
   U) URI_FILE=${OPTARG}
      ((count++));;
   F) FORCE=yes;;
   A) ALL=yes;;
   esac
   if ((count > 1)); then
       echo "Only one of date, uri or uri-file may be supplied" >&2
       exit 1
   fi
done

答案 2 :(得分:2)

创建一个由选项列表中每个互斥选项索引的关联数组,然后报告其大小是否大于1:

#!/bin/env bash

declare -A opts
while getopts ":d:u:U:hFA" opt; do
    case $opt in
    d) DATE=$OPTARG
       opts["$opt"]=1;;
    u) URI=${OPTARG}
       opts["$opt"]=1;;
    U) URI_FILE=${OPTARG}
       opts["$opt"]=1;;
    F) FORCE=yes;;
    A) ALL=yes;;
    esac
    if (( ${#opts[@]} > 1 )); then
        echo "Only one of date, uri or uri-file may be supplied" >&2
        exit 1
    fi
done

这将允许在命令行上存在同一选项的多个实例,而不允许有2个或更多不同选项的实例。