枚举数据类型似乎在bash中不可用

时间:2014-02-18 09:29:29

标签: linux bash enums

有了bash,用它的索引创建了用于访问数组元素的简单脚本。如下

#! /bin/bash

OK_INDEX=0
CANCEL_INDEX=1
ERROR_INDEX=2
CONFIRM_INDEX=3
SAVE_INDEX=4
EXIT_INDEX=5
declare -a messageList=("ok" 
                        "cancel" 
                        "error" 
                        "confirm"
                        "save"
                        "exit")

printf "%s \n" ${messageList[$CANCEL_INDEX]}

从上面的脚本我需要声明正确的索引变量来从数组列表中检索有效的消息但是我可能不方便我声明每个变量并给它们索引。如果变量自动获取值就像在C中一样很好ENUM数据类型

中可以通过

来实现
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX,CONFIRM_INDEX,SAVE_INDEX,EXIT_INDEX};

bash中有ENUM的替代方法吗?

我发现很多但没有成功然后尝试了一些技巧来实现这一点,如下所示

ENUM=(OK_INDEX CANCEL_INDEX ERROR_INDEX CONFIRM_INDEX SAVE_INDEX EXIT_INDEX)

maxArg=${#ENUM[@]}

for ((i=0; i < $maxArg; i++)); do
    name=${ENUM[i]}
    declare -r ${name}=$i
done

因此,在上面的代码片段中我成功创建了常量,但似乎冗长意味着只是声明变量我需要编写5-10行代码,这是不公平的。

那么任何人都有另一种解决方案吗?

4 个答案:

答案 0 :(得分:3)

尝试下面的代码片段......我想这就是你想要的

#!/bin/bash
set -u 
DEBUG=1

# This funcion allow to declare enum "types", I guess
enum ()
{
    # skip index ???
    shift
    AA=${@##*\{} # get string strip after { 
    AA=${AA%\}*} # get string strip before }
    AA=${AA//,/} # delete commaa  
    ((DEBUG)) && echo $AA
    local I=0
    for A in $AA ; do
        eval "$A=$I"
        ((I++))
    done
}

### Main program 
# Just declare enum as you need
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX, CONFIRM_INDEX, SAVE_INDEX, EXIT_INDEX };
# Print value of enumerated items
echo $OK_INDEX
echo $CANCEL_INDEX 
echo $ERROR_INDEX  
echo $CONFIRM_INDEX
echo $SAVE_INDEX
echo $EXIT_INDEX

# Use enumerated index in program
I=CONFIRM_INDEX
case $I in  
    OK_INDEX )
        echo "Process here when index is $I"
    ;;
    CANCEL_INDEX )
        echo "Process here when index is $I"
    ;;
    ERROR_INDEX )
        echo "Process here when index is $I"
    ;;
    CONFIRM_INDEX )
        echo "Process here when index is $I"
    ;;  
    SAVE_INDEX )
        echo "Process here when index is $I"
    ;;  
    EXIT_INDEX )
        echo "Process here when index is $I"
    ;;  
esac  

exit 0

答案 1 :(得分:1)

需要枚举时的典型解决方法是使用普通字符串。在这些情况下,我甚至省略了围绕变量评估的其他强制性报价:

 state=IDLE
 ...
 while [ $state = IDLE ]
 do
   ...
   if condition
   then
     state=BUSY
   fi
   ...
   if condition2
   then
     state=ERROR
   fi
   ...
 done
 if [ $state = ERROR ]
 then
   ...
 fi

这样,当然,您只具有命名状态的基本功能,而且以下两者通常都没有相关的枚举功能:

  1. 声明所有可能的值(自我记录代码)
  2. 每个值的相关数字(如果这是一个特征或疣,味道的问题)
  3. 没有预防/检测错误(但这在剧本中很少见)

答案 2 :(得分:1)

我对此:

function \
   _enum()
{
   ## void
   ## (
   ##    _IN $@ : [ array<string> ] list
   ## )

   local list=("$@")
   local len=${#list[@]}

   for (( i=0; i < $len; i++ )); do
      eval "${list[i]}=$i"
   done
}

示例:

ENUM=(
   OK_INDEX
   CANCEL_INDEX
   ERROR_INDEX
   CONFIRM_INDEX
   SAVE_INDEX
   EXIT_INDEX
) && _enum "${ENUM[@]}"

echo "OK_INDEX = "$OK_INDEX
echo "CANCEL_INDEX = "$CANCEL_INDEX
echo "ERROR_INDEX = "$ERROR_INDEX
echo "CONFIRM_INDEX = "$CONFIRM_INDEX
echo "SAVE_INDEX = "$SAVE_INDEX
echo "EXIT_INDEX = "$EXIT_INDEX

输出

OK_INDEX = 0
CANCEL_INDEX = 1
ERROR_INDEX = 2
CONFIRM_INDEX = 3
SAVE_INDEX = 4
EXIT_INDEX = 5

我发现这是最干净,最直接的方法。

另一种解决方案是将值分配给关联数组,以将变量名作为前缀的枚举集。通过遍历所有可用值及其关联的键名称,可以进行自省。

function \
   _enum_set()
{
   ## void
   ## (
   ##    _IN  $1 : [ string ] prefix
   ##    _IN ... : [ array<string> ] list
   ## )

   local prefix=$1
   local list=("$@")
   local len=${#list[@]}

   declare -g -A $prefix

   for (( i=0; i < $len; i++ )); do
      # Skip the first argument
      [[ $i = 0 ]] &&
         continue

      eval "$prefix[${list[$i]}]=$(( $i - 1 ))"
   done
}

示例(循环):

ENUM=(
   OK
   CANCEL
   ERROR
   CONFIRM
   SAVE
   EXIT
) && _enum_set ENUM_INDEX "${ENUM[@]}"

echo ""
for i in "${!ENUM_INDEX[@]}"; do
   echo "ENUM_INDEX[$i] = "${ENUM_INDEX[$i]}
done

输出:

ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[OK] = 0
ENUM_INDEX[EXIT] = 5
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[CANCEL] = 1

示例(明确):

ENUM=(
   OK
   CANCEL
   ERROR
   CONFIRM
   SAVE
   EXIT
) && _enum_set ENUM_INDEX "${ENUM[@]}"

echo "ENUM_INDEX[OK] = "${ENUM_INDEX[OK]}
echo "ENUM_INDEX[CANCEL] = "${ENUM_INDEX[CANCEL]}
echo "ENUM_INDEX[ERROR] = "${ENUM_INDEX[ERROR]}
echo "ENUM_INDEX[CONFIRM] = "${ENUM_INDEX[CONFIRM]}
echo "ENUM_INDEX[SAVE] = "${ENUM_INDEX[SAVE]}
echo "ENUM_INDEX[EXIT] = "${ENUM_INDEX[EXIT]}

输出:

ENUM_INDEX[OK] = 0
ENUM_INDEX[CANCEL] = 1
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[EXIT] = 5

请注意,关联数组没有定义的顺序,但始终可以在以后排序。

答案 3 :(得分:1)

您可以合并以下几行:

for i in E_OK E_CANCEL E_ERROR E_CONFIRM E_SAVE E_EXIT; do declare -r ${i}=$((x++)); done

输出:

for i in ${!E_@}; do echo $i=${!i}; done

E_CANCEL=1
E_CONFIRM=3
E_ERROR=2
E_EXIT=5
E_OK=0
E_SAVE=4