배열 요소에 대한 단항 테스트 -v

배열 요소에 대한 단항 테스트 -v

Bash에서 단항 테스트를 사용하는 조건식은 -v myvariable변수가 myvariable설정되었는지 여부를 테스트합니다. myvariable달러를 앞에 붙여서 확장하면 안 된다는 점에 유의하세요 .아니요 $myvariable. 이제 배열 요소의 경우 조건식은 -v myarray[index]전체 확장 구문 없이도 잘 작동한다는 것을 알았습니다 ${myarray[$index]}. 이 시도:

    myarray[2]=myvalue
    for i in 1 2 3
    do
        [ -v myarray\[i] ] && echo element $i is set
    done

\[( 따옴표를 사용하는 대신 와일드카드를 방지하기 위해 이스케이프 처리에 유의하세요 )

원하는 출력을 제공합니다.

    element 2 is set

질문 이 동작을 사용해도 안전한가요?또한 ~으로 알려진이것이 문서화 된 동작입니까?

부록 답변을 읽은 후https://unix.stackexchange.com/a/677920/376817Stéphane Chazelas의 예를 확장했습니다.

    myarray[1]=val myarray[2]=val myarray[3]=val myarray[4]=val myarray[5]=val myarray[6]="" myarray[2]=""
    unset myarray[3] myarray[4] myarray[5]
    touch myarray4 myarrayi
    myarray4=val myarrayi=val

그 다음에

    for i in {0..7}; do [ -v myarray\[i] ] && echo element $i is set; done

주어진

    element 1 is set
    element 2 is set
    element 6 is set

인덱스 표현식을 인용하거나 이스케이프하지 마십시오 [i].

    for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done

주어진

    element 0 is set
    element 1 is set
    element 2 is set
    element 3 is set
    element 4 is set
    element 5 is set
    element 6 is set
    element 7 is set

변수 unset과 동일 myarrayi:

    unset myarrayi
    for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done

주어진

    %nothing%

마지막으로 색인을 다음으로 확장합니다 $i(여전히 대괄호를 인용하거나 이스케이프 처리하지 않음).

    for i in {0..7}; do [ -v myarray[$i] ] && echo element $i is set; done

그것은 준다

    element 1 is set
    element 2 is set
    element 4 is set

왜냐하면

    ls -l myarray*

프로그램

    -rw-rw-r-- 1 me us 0 nov 17 15:37 myarray4
    -rw-rw-r-- 1 me us 0 nov 17 15:37 myarrayi

답변1

에서는 bash다음을 수행할 수 있습니다.

[ -v 'a[2]' ]

또는

[[ -v a[2] ]]

인덱스 2의 배열 요소 또는 키 "2"의 연관 배열 요소가 설정되었는지 테스트하려면(빈 문자열에도 불구하고) 다음 사항에 유의하세요.

  • [(일명 ) 명령을 사용할 때는 와일드카드이므로 따옴표 와 문자가 test필요합니다 . 일반 명령이기 때문에 다른 일반 명령처럼 해석되므로 in 은 or 와 같은 방식으로 확장 됩니다 . 현재 작업 디렉터리에 호출된 파일이 있으면 해당 파일로 확장됩니다. 그렇지 않은 경우 활성화되거나 비어 있는 상태로 확장되거나 각각 오류가 발생합니다. 자체 구문이 있는 특수 구조이므로 문제가 없습니다.[][a[2][ -v a[2] ]ls -d a[2]unset a[2]a2a[2]nullglobfailgloba[2][[ ... ]]

  • 연관 배열(테스트한 버전 5.1 이상)의 경우 확인하려는 키가 변수에 있는 경우 최신 버전에 도입된 옵션 뿐만 아니라 또는 이 $i필요합니다.[ -v 'a[$i]' ][[ -v 'a[$i]' ]]assoc_expand_oncebash 아니요사용 가능. 또는 백슬래시를 포함하는 일부 값에는 [ -v "a[$i]" ]or 를 사용할 수 없습니다 [[ -v a[$i] ]]. 거기에는 인용이 필요합니다. 당신은 또한 볼 수 있습니다$i]$산술 표현식에서 연관 배열을 안전하게 사용하는 방법은 무엇입니까?.

  • 연관 배열의 경우에도 bash(복사 시도와 반대로 ksh93) 널 키는 지원 bash되지 않습니다 . and 를 빈 문자열로 zsh사용하면 오류가 발생합니다. 따라서 임의의 키 값을 테스트하려면 또는 를 사용하십시오 .[[ -v 'a[$i]' ]]$i[[ -n $i && -v 'a[$i]' ]][ -n "$i" ] && [ -v 'a[$i]' ]

  • 일반(희소) 배열의 경우 in [ -v 'a[expr]' ]또는 [[ -v a[expr] ]]expr산술 표현식으로 평가됩니다. 이것이 i와 둘 다 $i작동하는 이유입니다. 산술 표현식은 변수를 할당하거나 임의 명령을 실행하는 부작용을 가질 수 있으므로 $i사용된 값을 [ -v 'a[i]' ]삭제하는 것이 중요합니다 . 그렇지 않으면 임의 명령 실행 취약점에 노출됩니다. 본 것처럼bash/POSIX 쉘에서 변수를 인용하는 것을 잊어버리는 보안 위험bash, 배열 인덱싱에 적용할 수 있다는 사실 [ -v lvalue ]로 인해 [ -f $file ](저자가 인용하는 것을 잊음 $file) ACE 취약점과 같은 문제가 발생했습니다.

  • [ -n "${var+set}" ]어떤 경우든 (연관) 배열 요소( )에 적용되는 Bourne/POSIX 메서드를 항상 사용할 수 있습니다. [ -n "${a[$key]+set}" ]해결 방법이 필요하지 않으며 모든 배열 인식 bash 버전(2.0(1996) 이상 이후 버전) 또는 연관 배열 지원에서 작동합니다. (4.0 (2009) 이상), 쉘 간에 이식 가능합니다.

  • 이는 [ -v var ]사실상 와 동일하다는 점에 유의하세요 [ -v 'var[0]' ]. ksh88에서와 같이 스칼라 변수는 배열 인덱스 0의 요소로 처리될 수 있습니다.

  • 배열 또는 연관 배열에 요소가 있는지(또는 스칼라 변수 세트가 있는지) 확인하려면 [ "${#a[@]}" -gt 0 ]또는 [ -v 'a[@]' ]또는 를 수행할 수도 있습니다 [ -v 'a[*]' ].2023년 편집, 처럼@johnraff가 지적함, 버전 5.2부터 후자의 두 가지는 5.1 호환성이 활성화되지 않는 한 더 이상 연관 배열에 적용되지 않습니다.

  • 희소 배열의 인덱스나 연관 배열의 키를 반복하려면 다음을 수행할 수 있습니다.

    for key in "${!a[@]}"; do
      printf 'The element of key "%s" is set\n' "$key"
    done
    

    ( 0스칼라 변수가 주어짐)

기록 여부는 다음과 같습니다. info bash test또는 을 실행하면 다음과 info bash '['같은 결과가 나타납니다.바라보다그것은 따른다Bash 조건식(내부적으로 사용되는 경우 [[ ... ]]) 문서는 -v다음과 같습니다.

-v VARNAME
쉘 변수 VARNAME이 설정(할당)되면 참입니다.

다음 help test이 있지만:

 -v VAR         True if the shell variable VAR is set.

VARNAME그것이 무엇인지 (특히 배열 멤버가 허용되는 경우) 또는 VARNAME참조가 스칼라 변수가 아닌 변수에 대한 것인 경우 수행할 작업에 대한 명시적인 사양은 없습니다 . 그러나 a[x]이는 일반적으로 변수 이름이 필요할 때마다 허용되고 수십 년 동안 그래왔음을 고려하면 앞으로도 계속 그렇게 될 것이라고 안전하게 가정할 수 있습니다.

해당 공식 문서의 다른 부분을 보면 일반적으로 변수 이름이 예상되는 곳이면 어디든(호출 여부에 관계없이) 암시한다는 것을 알 수 있습니다.이름,VAR,변수 이름또는 더 일반적으로범위), varname[index]또한 허용됩니다. 예를 들어, unset자체 문서(info bash unset), 언급되지 unset 'array[i]'않았지만배열에 관한 부분.

이것NEWS소스 배포판(릴리스 노트)의 문서에 따르면 test -vbash-4.2(2011)에 추가되었다고 나와 있는데, 아마도 얼마 전(2009년) ksh93t+에 추가한 ksh93에서 영감을 받은 것 같습니다. 자체 배열 요소 지원은 릴리스 노트에 언급되어 있습니다. )

에프. test// "변수"가 설정된 경우 성공을 반환하는 새로운 변수 단항 연산자 [가 있습니다 .[[-v

4.3에서는:

둘. test// 이제 [이진 연산자는 [[ -v variable배열 참조를 이해합니다.

5.1에서:

엑스. test -v N이제 위치 매개변수 N이 설정되었는지 테스트할 수 있습니다.

CWRU/changelog소스 코드 배포에서 연관 배열 test -v array[@]또는 연관 배열에 대한 참조를 찾을 수 있는데 [[ -v array[$key] ]], 이는 이 기능이 의도적인 것임을 다시 한번 시사합니다.

인용을 요구하는 등 제가 언급한 해결 방법을 무효화할 수 있는 위의 문제 중 일부를 해결하기 위해 미래에 조치를 취할 수 있는 것은 불가능하지 않습니다 $.

답변2

Bash 5.2에서는 연관 배열에 가 있는 요소가 포함되어 있는지 여부를 더 이상 테스트할 수 없으며 test -v 'arr[@]', 이제 "@"라는 키에 대해 특별히 테스트됩니다.

나는 그렇게 생각하거나 test "${#arr[@]}" -gt 0그렇게 (( ${#k[@]} > 0 ))할 것이다.

compat51을 참조하세요:https://www.gnu.org/software/bash/manual/bash.html#Shell-Compatibility-Mode

관련 정보