bash 检查数组中的索引或键的最简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13219634/
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-09 22:55:06  来源:igfitidea点击:

Easiest way to check for an index or a key in an array?

arraysbashindexingkey

提问by Luca Borrione

Using:

使用:

set -o nounset

1) Having an indexed array like:

1)有一个索引数组,如:

myArray=( "red" "black" "blue" )

What is the shortest way to check if element 1 is set?
I sometimes use the following:

检查元素 1 是否设置的最短方法是什么?
我有时会使用以下内容:

test "${#myArray[@]}" -gt "1" && echo "1 exists" || echo "1 doesn't exist"

I would like to know if there's a preferred one.

2) How to deal with non-consecutive indexes?

我想知道是否有首选的。

2)如何处理非连续索引?

myArray=()
myArray[12]="red"
myArray[51]="black"
myArray[129]="blue"

How to quick check that '51' is already set for example?

3) How to deal with associative arrays?

例如,如何快速检查“51”是否已设置?

3)如何处理关联数组?

declare -A myArray
myArray["key1"]="red"
myArray["key2"]="black"
myArray["key3"]="blue"

How to quick check that 'key2' is already used for example?

Thanks

例如,如何快速检查“key2”是否已被使用?

谢谢

EDITED
The simplest way seems to me:

编辑
在我看来最简单的方法:

if test "${myArray['key_or_index']+isset}"
    then
        echo "yes"
    else
        echo "no"
fi;

This works for both indexed and associative arrays. No errors shown with set -o nounset.
Thanks to doubleDown for the headup.

这适用于索引数组和关联数组。set -o nounset 没有显示错误。
感谢 doubleDown 的抬头。

回答by doubleDown

To check if the element is set (applies to both indexed and associative array)

检查元素是否已设置(适用于索引数组和关联数组)

[ ${array[key]+abc} ] && echo "exists"

Basically what ${array[key]+abc}does is

基本上,${array[key]+abc}做的是

  • if array[key]is set, return abc
  • if array[key]is not set, return nothing
  • 如果array[key]设置,返回abc
  • 如果array[key]未设置,则不返回任何内容



参考:

  1. See Parameter Expansionin Bash manual and the little note

    if the colon is omitted, the operator tests only for existence [of parameter]

  2. This answer is actually adapted from the answers for this SO question: How to tell if a string is not defined in a bash shell script?

  1. 请参阅Bash 手册中的参数扩展和小注释

    如果省略冒号,则运算符仅测试 [of parameter]是否存在

  2. 这个答案实际上改编自这个问题的答案:如何判断字符串是否未在 bash shell 脚本中定义



A wrapper function:

一个包装函数:

exists(){
  if [ "" != in ]; then
    echo "Incorrect usage."
    echo "Correct usage: exists {key} in {array}"
    return
  fi   
  eval '[ ${''[]+muahaha} ]'  
}

For example

例如

if ! exists key in array; then echo "No such array element"; fi 

回答by Vineet

From man bash, conditional expressions:

man bash,条件表达式:

-v varname
              True if the shell variable varname is set (has been assigned a value).

example:

例子:

declare -A foo
foo[bar]="this is bar"
foo[baz]=""
if [[ -v "foo[bar]" ]] ; then
  echo "foo[bar] is set"
fi
if [[ -v "foo[baz]" ]] ; then
  echo "foo[baz] is set"
fi
if [[ -v "foo[quux]" ]] ; then
  echo "foo[quux] is set"
fi

This will show that both foo[bar] and foo[baz] are set (even though the latter is set to an empty value) and foo[quux] is not.

这将显示 foo[bar] 和 foo[baz] 都已设置(即使后者设置为空值)而 foo[quux] 未设置。

回答by F. Hauri

New answer

新答案

From version 4.2 of bash(and newer), there is a new -voption to built-in testcommand.

bash4.2 版(和更新版本)开始,-v内置test命令有一个新选项 。

array=([12]="red" [51]="black" [129]="blue")

for i in 10 12 30 {50..52} {128..131};do
    if [ -v array[i] ];then
        echo "Variable 'array[$i]' is defined"
    else
        echo "Variable 'array[$i]' not exist"
    fi
done
Variable 'array[10]' not exist
Variable 'array[12]' is defined
Variable 'array[30]' not exist
Variable 'array[50]' not exist
Variable 'array[51]' is defined
Variable 'array[52]' not exist
Variable 'array[128]' not exist
Variable 'array[129]' is defined
Variable 'array[130]' not exist
Variable 'array[131]' not exist

This work with associative arraysin same way:

这以相同的方式与关联数组一起工作:

declare -A aArray=([foo]="bar" [bar]="baz" [baz]=$'Hello world1')

for i in alpha bar baz dummy foo test;do
    if [ -v aArray[$i] ];then
        echo "Variable 'aArray[$i]' is defined"
    else
        echo "Variable 'aArray[$i]' not exist"
    fi
done
Variable 'aArray[alpha]' not exist
Variable 'aArray[bar]' is defined
Variable 'aArray[baz]' is defined
Variable 'aArray[dummy]' not exist
Variable 'aArray[foo]' is defined
Variable 'aArray[test]' not exist

With a little difference:
In regular arrays, variable between brackets ([i]) is integer, so dollar symbol ($) is not required, but for associative array, as keyis a word, $is required ([$i])!

有一点区别:
在常规数组中,括号 ( [i])之间的变量是整数,因此$不需要美元符号 ( ),但对于关联数组,由于key是一个单词,$因此需要 ( [$i])!

Old answer for bashprior to V4.2

V4.2 之前的bash旧答案

Unfortunately, bash give no way to make difference betwen emptyand undefinedvariable.

不幸的是,bash 无法区分变量和未定义变量。

But there is some ways:

但是有一些方法:

$ array=()
$ array[12]="red"
$ array[51]="black"
$ array[129]="blue"

$ echo ${array[@]}
red black blue

$ echo ${!array[@]}
12 51 129

$ echo "${#array[@]}"
3

$ printf "%s\n" ${!array[@]}|grep -q ^51$ && echo 51 exist
51 exist

$ printf "%s\n" ${!array[@]}|grep -q ^52$ && echo 52 exist

(give no answer)

(不回答)

And for associative array, you could use the same:

对于关联数组,您可以使用相同的:

$ unset array
$ declare -A array
$ array["key1"]="red"
$ array["key2"]="black"
$ array["key3"]="blue"
$ echo ${array[@]}
blue black red

$ echo ${!array[@]}
key3 key2 key1

$ echo ${#array[@]}
3

$ set | grep ^array=
array=([key3]="blue" [key2]="black" [key1]="red" )

$ printf "%s\n" ${!array[@]}|grep -q ^key2$ && echo key2 exist || echo key2 not exist
key2 exist

$ printf "%s\n" ${!array[@]}|grep -q ^key5$ && echo key5 exist || echo key5 not exist
key5 not exist

You could do the job without the need of externals tools (no printf|grep as pure bash), and why not, build checkIfExist()as a new bash function:

你可以在不需要外部工具的情况下完成这项工作(没有 printf|grep 作为纯 bash),为什么不,将checkIfExist()构建为一个新的 bash 函数:

$ checkIfExist() {
    eval 'local keys=${!''[@]}';
    eval "case '' in
        ${keys// /|}) return 0 ;;
        * ) return 1 ;;
      esac";
}

$ checkIfExist array key2 && echo exist || echo don\'t
exist

$ checkIfExist array key5 && echo exist || echo don\'t
don't

or even create a new getIfExistbash function that return the desired value and exit with false result-code if desired value not exist:

或者甚至创建一个新的getIfExistbash 函数,该函数返回所需的值,如果所需的值不存在,则以 false 结果代码退出:

$ getIfExist() {
    eval 'local keys=${!''[@]}';
    eval "case '' in
        ${keys// /|}) echo ${[]};return 0 ;;
        * ) return 1 ;;
      esac";
}

$ getIfExist array key1
red
$ echo $?
0

$ # now with an empty defined value
$ array["key4"]=""
$ getIfExist array key4

$ echo $?
0
$ getIfExist array key5
$ echo $?
1

回答by gdoubleod

tested in bash 4.3.39(1)-release

在 bash 4.3.39(1)-release 中测试

declare -A fmap
fmap['foo']="boo"

key='foo'
# should echo foo is set to 'boo'
if [[ -z "${fmap[${key}]}" ]]; then echo "$key is unset in fmap"; else echo "${key} is set to '${fmap[${key}]}'"; fi
key='blah'
# should echo blah is unset in fmap
if [[ -z "${fmap[${key}]}" ]]; then echo "$key is unset in fmap"; else echo "${key} is set to '${fmap[${key}]}'"; fi

回答by sjas

This is the easiest way I found for scripts.

这是我为脚本找到的最简单的方法。

<search>is the string you want to find, ASSOC_ARRAYthe name of the variable holding your associative array.

<search>是您要查找的字符串,ASSOC_ARRAY即保存关联数组的变量的名称。

Dependign on what you want to achieve:

取决于您想要实现的目标:

key exists:

键存在

if grep -qe "<search>" <(echo "${!ASSOC_ARRAY[@]}"); then echo key is present; fi

key exists not:

键不存在

if ! grep -qe "<search>" <(echo "${!ASSOC_ARRAY[@]}"); then echo key not present; fi

value exists:

值存在

if grep -qe "<search>" <(echo "${ASSOC_ARRAY[@]}"); then echo value is present; fi

value exists not:

值不存在

if ! grep -qe "<search>" <(echo "${ASSOC_ARRAY[@]}"); then echo value not present; fi

回答by Lucas Stad

I wrote a function to check if a key exists in an array in Bash:

我编写了一个函数来检查 Bash 中的数组中是否存在一个键:

# Check if array key exists
# Usage: array_key_exists $array_name $key
# Returns: 0 = key exists, 1 = key does NOT exist
function array_key_exists() {
    local _array_name=""
    local _key=""
    local _cmd='echo ${!'$_array_name'[@]}'
    local _array_keys=($(eval $_cmd))
    local _key_exists=$(echo " ${_array_keys[@]} " | grep " $_key " &>/dev/null; echo $?)
    [[ "$_key_exists" = "0" ]] && return 0 || return 1
}

Example

例子

declare -A my_array
my_array['foo']="bar"

if [[ "$(array_key_exists 'my_array' 'foo'; echo $?)" = "0" ]]; then
    echo "OK"
else
    echo "ERROR"
fi

Tested with GNU bash, version 4.1.5(1)-release (i486-pc-linux-gnu)

使用 GNU bash 测试,版本 4.1.5(1)-release (i486-pc-linux-gnu)

回答by GuyPaddock

What about a -ztest and the :-operator?

怎么样一个-z测试和:-运营商?

For example, this script:

例如,这个脚本:

#!/usr/bin/env bash

set -e
set -u

declare -A sample

sample["ABC"]=2
sample["DEF"]=3

if [[ ! -z "${sample['ABC']:-}" ]]; then
  echo "ABC is set"
fi

if [[ ! -z "${sample['DEF']:-}" ]]; then
  echo "DEF is set"
fi

if [[ ! -z "${sample['GHI']:-}" ]]; then
  echo "GHI is set"
fi

Prints:

印刷:

ABC is set
DEF is set