วิธีที่ง่ายที่สุดในการตรวจสอบดัชนีหรือคีย์ในอาร์เรย์


92

ใช้:

set -o nounset
  1. มีอาร์เรย์ที่จัดทำดัชนีเช่น:

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

    วิธีที่สั้นที่สุดในการตรวจสอบว่าองค์ประกอบ 1 ถูกตั้งค่าไว้หรือไม่
    บางครั้งฉันใช้สิ่งต่อไปนี้:

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

    ฉันต้องการทราบว่ามีที่ต้องการหรือไม่

  2. จะจัดการกับดัชนีที่ไม่ต่อเนื่องได้อย่างไร?

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

    วิธีการตรวจสอบด่วนที่51กำหนดไว้แล้วเช่น?

  3. จะจัดการกับ Associative Arrays ได้อย่างไร?

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

    วิธีการตรวจสอบด่วนที่key2ใช้อยู่แล้วเช่น?

คำตอบ:


134

เพื่อตรวจสอบว่าองค์ประกอบถูกตั้งค่า (ใช้กับอาร์เรย์ที่จัดทำดัชนีและเชื่อมโยง)

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

โดยพื้นฐาน${array[key]+abc}แล้วคืออะไร

  • หากarray[key]ตั้งค่าไว้ให้ส่งคืนabc
  • หากarray[key]ไม่ได้ตั้งค่าจะไม่ส่งคืนอะไรเลย


อ้างอิง:

  1. ดูการขยายพารามิเตอร์ในคู่มือ Bash และหมายเหตุเล็กน้อย

    หากไม่ใส่เครื่องหมายทวิภาคตัวดำเนินการจะทดสอบเฉพาะการมีอยู่ [ของพารามิเตอร์ ]

  2. คำตอบนี้ดัดแปลงมาจากคำตอบสำหรับคำถาม SO นี้: จะทราบได้อย่างไรว่าสตริงไม่ได้กำหนดไว้ใน bash shell script ?


ฟังก์ชัน Wrapper:

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

ตัวอย่างเช่น

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

ฉันแก้ไขด้วยวิธีนี้: ถ้าทดสอบ "$ {myArray ['key_or_index'] + isset}"; แล้วสะท้อนว่า "ใช่"; อื่นสะท้อน "ไม่"; ไฟ; สำหรับฉันแล้วดูเหมือนว่าเป็นวิธีที่ง่ายที่สุดและใช้ได้กับอาร์เรย์ที่จัดทำดัชนีและเชื่อมโยง ขอบคุณ
Luca Borrione

1
@doubleDown คุณจะใช้ [$ {array [key] + abc}] ในประโยค if เพื่อทำบางสิ่งได้อย่างไรถ้าไม่มี [$ {array [key] + abc}]
olala

1
ยังใช้ไม่ได้เมื่อคุณค้นหาอาร์เรย์ที่ระบุโดยไม่ได้ตั้งใจว่าเป็นตัวเชื่อมโยง
Tomáš Zato - คืนสถานะ Monica

1
@duanev: โดยไม่ต้อง+abc, [ ${array[key]} ]จะประเมินเป็นเท็จถ้าองค์ประกอบที่ถูกกำหนดแน่นอน แต่เป็นค่าว่างเปล่าดังนั้นมันจริงการทดสอบค่าที่ไม่ใช่ความว่างเปล่ามากกว่าการดำรงอยู่ที่สำคัญ
musiphil

@duanev โดยไม่+abcล้มเหลวเมื่อarray[key]ไม่ได้ตั้งค่าและset -uมีผลบังคับใช้
Ding-Yi Chen

36

จากman bashนิพจน์เงื่อนไข:

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

ตัวอย่าง:

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

สิ่งนี้จะแสดงว่าทั้ง foo [bar] และ foo [baz] ถูกตั้งค่า (แม้ว่าจะตั้งค่าหลังเป็นค่าว่าง) และไม่ได้ตั้งค่า foo [quux]


1
ฉันพลาดไปอย่างรวดเร็ว สังเกตว่าไม่ได้ใช้ไวยากรณ์การขยายอาร์เรย์ทั่วไป
Nathan Chappell

ด้วยset -uเหตุใดจึง[[ -v "${foo[bar]}" ]]สร้างข้อผิดพลาดตัวแปร unbound หากbarไม่มีอยู่ในพจนานุกรม ทำงานได้ดีโดยไม่ต้อง${}; ฉันเพิ่งเคยใช้มันกับทุกอย่างโดยปริยาย
bgfvdu3w

"${foo[bar]}"ประเมินตัวแปรอาร์เรย์ก่อนดังนั้น[[ -vคำสั่งจะทดสอบตัวแปรที่มีชื่อของค่านั้น
andysh

12

คำตอบใหม่

จากเวอร์ชัน 4.2 ของ (และใหม่กว่า) มี-vตัวเลือกใหม่สำหรับtestคำสั่งใน ตัว

จากเวอร์ชัน 4.3 การทดสอบนี้สามารถระบุองค์ประกอบของอาร์เรย์ได้

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

ทำงานกับอาร์เรย์ที่เชื่อมโยงในลักษณะเดียวกัน:

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

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

ด้วยความแตกต่างเล็กน้อย:
ในอาร์เรย์ปกติตัวแปรระหว่างวงเล็บ ( [i]) เป็นจำนวนเต็มดังนั้นจึง$ไม่จำเป็นต้องใช้สัญลักษณ์ดอลลาร์ ( ) แต่สำหรับอาร์เรย์ที่เชื่อมโยงกันเนื่องจากคีย์เป็นคำ$จำเป็นต้องมี ( [$i])!

คำตอบเก่าสำหรับ ก่อนหน้า V4.2

น่าเสียดายที่ 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

(ไม่ตอบ)

และสำหรับ Associative array คุณสามารถใช้สิ่งเดียวกัน:

$ 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

คุณสามารถทำงานได้โดยไม่ต้องใช้เครื่องมือภายนอก (no printf | grep as pure 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

หรือแม้กระทั่งสร้างฟังก์ชัน bash getIfExistใหม่ที่ส่งคืนค่าที่ต้องการและออกด้วยรหัสผลลัพธ์ที่เป็นเท็จหากไม่มีค่าที่ต้องการ:

$ 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

ตกลงสำหรับ downvotes: คำตอบนี้โพสต์ก่อน V4.2 ของbash ! แก้ไขคำตอบแล้ว!
F. Hauri

bash 4.2.46ไม่ทำงานบน bash 4.4.12ทำงานบน
Irfy

@Irfy ไม่ทำงานอะไร -vตัวเลือกtestหรือgetIfExistฟังก์ชัน?
F. Hauri

1
-vถูกเพิ่มลงใน bash-4.2 แต่การสนับสนุนสำหรับการตรวจสอบดัชนีอาร์เรย์ไม่ได้ถูกเพิ่มจนกว่า bash-4.3
mr.spuratic

1
@ mr.spuratic ขอบคุณสำหรับความคิดเห็น!
F. Hauri

5

ทดสอบใน bash 4.3.39 (1) - ปล่อย

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

ซึ่งจะล้มเหลวเมื่อค่าของคีย์เป็นสตริงว่าง ในการแก้ปัญหาชั่วคราวคุณสามารถใช้การ+ขยายพารามิเตอร์เพื่อแทนที่ค่าว่างด้วยตัวยึดบางอย่างเช่นขีดล่าง ตัวอย่างเช่นdeclare -A a[x]=;[[ ${a[x]} ]];echo $?พิมพ์1แต่พิมพ์declare -A a[x]=;[[ ${a[x]+_} ]];echo $? 0
nisetama

3

แล้วการ-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

พิมพ์:

ABC is set
DEF is set

โซลูชันขนาดกะทัดรัดที่ยอดเยี่ยมซึ่งตอบสนองตามที่คาดไว้สำหรับสตริงว่าง
Ryan Dugan

1

นี่เป็นวิธีที่ง่ายที่สุดที่ฉันพบสำหรับสคริปต์

<search> คือสตริงที่คุณต้องการค้นหา ASSOC_ARRAYชื่อของตัวแปรที่มีอาร์เรย์เชื่อมโยงของคุณ

ขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุ:

มีคีย์อยู่ :

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

ไม่มีคีย์ :

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

มีค่า :

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

ไม่มีค่า :

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

1

ฉันเขียนฟังก์ชันเพื่อตรวจสอบว่ามีคีย์อยู่ในอาร์เรย์ใน 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="$1"
    local _key="$2"
    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
}

ตัวอย่าง

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

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

ทดสอบด้วย GNU bash เวอร์ชัน 4.1.5 (1) - ปล่อย (i486-pc-linux-gnu)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.