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

Luc*_*one 77 arrays indexing bash key

使用:

set -o nounset
Run Code Online (Sandbox Code Playgroud)

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

myArray=( "red" "black" "blue" )
Run Code Online (Sandbox Code Playgroud)

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

test "${#myArray[@]}" -gt "1" && echo "1 exists" || echo "1 doesn't exist"
Run Code Online (Sandbox Code Playgroud)

我想知道是否有一个首选的.

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

myArray=()
myArray[12]="red"
myArray[51]="black"
myArray[129]="blue"
Run Code Online (Sandbox Code Playgroud)

如何快速检查'51'已经设置好了?

3)如何处理关联数组?

declare -A myArray
myArray["key1"]="red"
myArray["key2"]="black"
myArray["key3"]="blue"
Run Code Online (Sandbox Code Playgroud)

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

谢谢

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

if test "${myArray['key_or_index']+isset}"
    then
        echo "yes"
    else
        echo "no"
fi;
Run Code Online (Sandbox Code Playgroud)

这适用于索引和关联数组.set -o nounset没有显示错误.
感谢headDown为headup.

dou*_*own 115

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

[ ${array[key]+abc} ] && echo "exists"
Run Code Online (Sandbox Code Playgroud)

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

  • 如果array[key]设置,则返回abc
  • 如果array[key]没有设置,则不返回任何内容


参考文献:

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

    如果省略冒号,则运算符仅测试[ 参数 ]的存在

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


包装函数:

exists(){
  if [ "$2" != in ]; then
    echo "Incorrect usage."
    echo "Correct usage: exists {key} in {array}"
    return
  fi   
  eval '[ ${'$3'[$1]+muahaha} ]'  
}
Run Code Online (Sandbox Code Playgroud)

例如

if ! exists key in array; then echo "No such array element"; fi 
Run Code Online (Sandbox Code Playgroud)

  • 如果`key`包含空格,则不起作用. (4认同)
  • **但是 `eval` 是邪恶的!!** 试试这个:`exists foo in 'O};cat /etc/passwd;echo -e \\e[5m'` 作为示例! (3认同)
  • @duanev:如果没有 `+abc`,如果元素确实设置但为空值,则 `[ ${array[key]} ]` 将计算为 false,因此它实际上是在测试值非空而不是键是否存在。 (2认同)

Vin*_*eet 22

man bash,条件表达式:

-v varname
              True if the shell variable varname is set (has been assigned a value).
Run Code Online (Sandbox Code Playgroud)

例:

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
Run Code Online (Sandbox Code Playgroud)

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

  • 我一眼就错过了;请注意,未使用典型的数组扩展语法。 (3认同)
  • `"${foo[bar]}"` 首先评估数组变量,因此 `[[ -v` 命令测试具有该值名称的变量 (3认同)

Guy*_*ock 8

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

例如,这个脚本:

#!/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
Run Code Online (Sandbox Code Playgroud)

印刷:

ABC is set
DEF is set
Run Code Online (Sandbox Code Playgroud)


F. *_*uri 6

不幸的是,bash没有办法在变量和未定义变量之间产生差异.

但有一些方法:

$ 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
Run Code Online (Sandbox Code Playgroud)

(不回答)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

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

$ checkIfExist() {
    eval 'local keys=${!'$1'[@]}';
    eval "case '$2' 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
Run Code Online (Sandbox Code Playgroud)

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

$ getIfExist() {
    eval 'local keys=${!'$1'[@]}';
    eval "case '$2' in
        ${keys// /|}) echo \${$1[$2]};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
Run Code Online (Sandbox Code Playgroud)

  • 整个页面证明了 bash 的巨大失败。对于最基本的事情,它充满了 20 种反直觉的方法,并且都带有诸如“(不)适合我/这个或那个版本”之类的评论。 (5认同)
  • `-v` 被添加到 bash-4.2 *但是* 对检查数组索引的支持直到 bash-4.3 才添加。 (2认同)
  • 谢谢,在 macOS/brew bash 5.1.8 上对我来说效果很好:-) `shellcheck` 报告 [SC2208](https://github.com/koalaman/shellcheck/wiki/SC2208) 对于两个_新答案_代码示例:显然, `if` 应该使用 `[[ ... ]]` 而不是 `[ ... ]` 或者 `-v` 之后的表达式应该被引用,例如 `if [[ -v aArray[$i] ]] ` 或 `if [ -v 'aArray[$i]' ]`。打败了我,我通常只做“shellcheck”告诉我的事情...... (2认同)

gdo*_*eod 5

在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
Run Code Online (Sandbox Code Playgroud)