배열에서 인덱스 또는 키를 확인하는 가장 쉬운 방법은 무엇입니까?


89

사용 :

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. 연관 배열을 다루는 방법은 무엇입니까?

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

    key2예를 들어 이미 사용중인 것을 빠르게 확인하는 방법 은 무엇입니까?

답변:


130

요소가 설정되었는지 확인하려면 (인덱싱 된 배열과 연관 배열에 모두 적용됨)

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

기본적으로하는 ${array[key]+abc}것은

  • 경우 array[key]설정, 반환abc
  • array[key]설정되지 않은 경우 아무것도 반환하지 않습니다.


참조 :

  1. 참조 매개 변수 확장 배쉬 설명서와 작은 노트

    콜론이 생략되면 연산자는 [ 매개 변수 ]의 존재 여부 만 테스트합니다 .

  2. 이 답변은 실제로이 질문에 대한 답변에서 채택 되었습니다. bash 쉘 스크립트에 문자열이 정의되어 있지 않은지 어떻게 알 수 있습니까?


래퍼 기능 :

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 

나는 이런 식으로 풀었다 : if test "$ {myArray [ 'key_or_index'] + isset}"; 그런 다음 "예"를 에코합니다. 그렇지 않으면 에코 "아니오"; fi; 나에게 가장 간단한 방법으로 보이며 인덱스 및 연관 배열에 적용됩니다. 감사합니다
Luca Borrione 2012

1
@doubleDown if 절에서 [$ {array [key] + abc}]를 사용하여 [$ {array [key] + abc}]가 존재하지 않는 경우에만 작업을 수행합니까?
olala 2014

1
또한 실수로 열거 형 배열을 연관 배열로 쿼리 할 때도 작동하지 않습니다.
토마스 Zato - 분석 재개 모니카

1
@duanev : Without +abc, [ ${array[key]} ]요소가 실제로 설정되었지만 빈 값이면 false로 평가되므로 실제로 키 존재가 아닌 값이 비어 있지 않은지 테스트합니다.
musiphil

@duanev 가 설정되지 않은 +abc경우에도 실패 array[key]하고 set -u효과적입니다.
Ding-Yi Chen

35

에서 남자 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 19

를 사용 하면 사전에없는 경우 바인딩되지 않은 변수 오류 set -u[[ -v "${foo[bar]}" ]]발생하는 이유는 bar무엇입니까? 없이 잘 작동합니다 ${}; 나는 기본적으로 모든 것을 사용하는 데 익숙합니다.
bgfvdu3w

"${foo[bar]}"배열 변수를 먼저 평가하므로 [[ -v명령은 해당 값의 이름을 가진 변수를 테스트합니다
andysh

10

새로운 답변

4.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

이것은 연관 배열 과 같은 방식으로 작동합니다.

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

(답변하지 않음)

그리고 연관 배열의 경우 다음과 같이 사용할 수 있습니다.

$ 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

외부 도구없이 작업을 수행 할 수 있으며 ( 순수 bash 로서 printf | grep 없음 ), 새로운 bash 함수로 checkIfExist () 를 빌드 하십시오 .

$ 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

또는 원하는 값을 반환하고 원하는 값이 없으면 거짓 결과 코드로 종료 하는 새로운 getIfExist bash 함수를 만들 수도 있습니다 .

$ 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에 대한 확인 :이 답변은 bash의 V4.2 이전에 게시되었습니다 ! 답변이 수정되었습니다!
F. Hauri

에서 작동하지 않습니다 bash 4.2.46. 에서 작동합니다 bash 4.4.12.
Irfy

@Irfy 작동하지 않는 것은 무엇입니까? -v옵션 test또는 getIfExist기능?
F. Hauri

-vbash는 4.2.46 내 CentOS는 1908년 7월 7일에 배열에서 작동하지 않습니다. 첫 번째 코드 블록의 코드는 not exist해당 bash 아래의 모든 경우에 인쇄 됩니다. ( [$i]대신 시도 [i], 차이 없음)
Irfy

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 2015

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.