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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21849328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 09:35:57  来源:igfitidea点击:

enum data type seems not available in bash

linuxbashenums

提问by Jayesh Bhoi

Having bash, created simple scripts for accessing array element by it's index.It as follows

有了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]}

from above scripts i need to declare proper index variable to retrieve valid message from array list but it likely not handy for me to declare each variable and give index to them.It is nice if variable autometically getting value as like in C for ENUMdata type

从上面的脚本中,我需要声明适当的索引变量以从数组列表中检索有效消息,但我声明每个变量并为它们提供索引可能不太方便。如果变量像在 C 中一样自动获取ENUM数据类型的值,那就太好了

in C it's possible by like

在 C 中,可以通过 like

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

is there any alternative for ENUMin bash?

ENUM在 bash 中有没有其他选择?

I found lot but not succeded then have try some trick to achieve this it is as follows

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

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

So form above code snippet i successfully created constant but it seems lengthy means just declaring variable i need to write 5-10 lines code which is not fair.

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

So any one have another solution?

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

采纳答案by abadjm

Try the following fragment of code ... I guess that it is what you want

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

#!/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

回答by bac0n

You can consolidate some of the lines:

您可以合并一些行:

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

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

Another version using mapfile callback function:

另一个使用 mapfile 回调函数的版本:

#!/bin/bash

mapfile -t -c 1 -C 'f(){ readonly =; }; f' << \
EOF
E_OK
E_CANCEL
E_ERROR
E_CONFIRM
E_SAVE
E_EXIT
EOF

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

Output:

输出:

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

回答by Zhro

My take on this:

我对此的看法:

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

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

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

Example:

例子:

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

Output

输出

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

I find this to be the cleanest and most straightforward approach.

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

Another solution is to assign values to an associative array to make an enum set with the variable name as the prefix. This allows introspection of the enum by walking through all available values and their associated key names:

另一种解决方案是将值分配给关联数组,以创建一个以变量名称作为前缀的枚举集。这允许通过遍历所有可用值及其关联的键名来内省枚举:

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

   local prefix=
   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
}

Example (looping):

示例(循环):

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

Output:

输出:

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

Example (explicit):

示例(显式):

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

Output:

输出:

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

Note that associative arrays have no defined order but can always be sorted at a later point.

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

回答by Alfe

The typical workaround when an enum is wanted is to use normal strings. In these cases I even omit the otherwise mandatory quotes around variable evaluation:

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

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

This way, of course, you have just the basic functionality of named states and neither of the following typically associated features of enums:

这样,当然,您只有命名状态的基本功能,而没有以下枚举的典型相关功能:

  1. declaration of all possible values (self-documenting code)
  2. associated number for each value (matter of taste if this is a feature or a wart)
  3. no prevention/detection of mistypings (but this is rare in scripts anyway)
  1. 声明所有可能的值(自记录代码)
  2. 每个值的相关数字(如果这是一个特征或一个疣,品味问题)
  3. 没有防止/检测错误输入(但这在脚本中很少见)