답변:
배열이이라고 가정하면 $errors
요소 개수가 0인지 확인하십시오.
if [ ${#errors[@]} -eq 0 ]; then
echo "No errors, hooray"
else
echo "Oops, something went wrong..."
fi
set -u
: "언 바운드 변수"-배열이 비어있는 경우
set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. I unset foo
이면을 인쇄 foo: unbound variable
하지만 다릅니다. 배열 변수는 존재하지 않고 비어 있지 않고 전혀 존재하지 않습니다.
set -u
변수를 먼저 선언 하는 한 Bash 3.2 (OSX)에서도 테스트되었습니다 . 이것은 완벽하게 작동합니다.
배열을 간단한 변수로 간주 할 수도 있습니다. 그런 식으로
if [ -z "$array" ]; then
echo "Array empty"
else
echo "Array non empty"
fi
또는 다른 쪽을 사용
if [ -n "$array" ]; then
echo "Array non empty"
else
echo "Array empty"
fi
해당 솔루션의 문제점은 배열이 다음과 같이 선언 된 경우 array=('' foo)
입니다. 이러한 검사는 어레이가 비어있는 것으로보고되지만 명확하지는 않습니다. (@musiphil 감사합니다!)
사용 [ -z "$array[@]" ]
하는 것도 해결책이 아닙니다. 중괄호를 지정하지 않으면 $array
문자열 ( [@]
이 경우 간단한 리터럴 문자열 임) 로 해석하려고 하므로 항상 거짓으로보고됩니다. "리터럴 문자열이 [@]
비어 있습니까?" 분명히 아닙니다.
[ -z "$array" ]
또는 [ -n "$array" ]
작동하지 않습니다. 를 시도 array=('' foo); [ -z "$array" ] && echo empty
하면 분명히 비어 있지 않은 empty
경우에도 인쇄됩니다 array
.
[[ -n "${array[*]}" ]]
전체 배열을 문자열로 보간하여 길이가 0이 아닌지 확인합니다. array=("" "")
비어있는 요소가 두 개가 아닌 비어있는 것으로 간주 하면 유용 할 수 있습니다.
[[ -n " " ]]
"true"이며 이는 유감입니다. 귀하의 의견은 정확히 내가 하고 싶은 일입니다.
set -x
그것이 어떻게 확장되는지 보여줍니다. 게시하기 전에 해당 주석을 테스트하지 않은 것 같습니다. >. < 확장은 요소를 IFS의 첫 문자로 분리 IFS=''
하므로 설정 (이 명령문 주위에 저장 / 복원) 하여 작업을 수행 할 수 있습니다 "${array[*]}"
. (설정되지 않은 경우 공간). 그러나 " IFS가 null 인 경우 매개 변수는 중간 구분 기호없이 연결됩니다. "($ * 위치 매개 변수에 대한 문서이지만 배열에 대해서는 동일하다고 가정)
나는 그것을 확인했다 bash-4.4.0
:
#!/usr/bin/env bash
set -eu
check() {
if [[ ${array[@]} ]]; then
echo not empty
else
echo empty
fi
}
check # empty
array=(a b c d)
check # not empty
array=()
check # empty
그리고 bash-4.1.5
:
#!/usr/bin/env bash
set -eu
check() {
if [[ ${array[@]:+${array[@]}} ]]; then
echo non-empty
else
echo empty
fi
}
check # empty
array=(a b c d)
check # not empty
array=()
check # empty
후자의 경우 다음 구성이 필요합니다.
${array[@]:+${array[@]}}
비어 있거나 설정되지 않은 배열에서 실패하지 않습니다. set -eu
내가 평소처럼 한다면 보다 엄격한 오류 검사를 제공합니다. 에서 워드 프로세서 :
-이자형
단일 단순 명령 (단순 명령 참조), 목록 (목록 참조) 또는 복합 명령 (복합 명령 참조)으로 구성 될 수있는 파이프 라인 (파이프 라인 참조)이 0이 아닌 상태를 반환하면 즉시 종료하십시오. 실패한 명령이 while 또는 until 키워드 바로 뒤에 나오는 명령 목록의 일부인 if 문의 테스트 부분, && 또는 ||에서 실행 된 명령의 일부인 경우 쉘이 종료되지 않습니다. 마지막 && 또는 || 뒤에 오는 명령, 파이프 라인의 마지막 명령이지만 마지막 명령 또는 명령의 반환 상태가!로 반전 된 경우를 제외하고 list. -e가 무시되는 동안 명령이 실패하여 서브 쉘 이외의 복합 명령이 0이 아닌 상태를 리턴하면 쉘이 종료되지 않습니다. 설정된 경우 ERR의 트랩은 쉘이 종료되기 전에 실행됩니다.
이 옵션은 쉘 환경과 각 서브 쉘 환경에 별도로 적용되며 (명령 실행 환경 참조) 서브 쉘에서 모든 명령을 실행하기 전에 서브 쉘이 종료 될 수 있습니다.
-e가 무시되는 상황에서 복합 명령 또는 쉘 함수가 실행되면 복합 명령 또는 함수 본문 내에서 실행 된 명령은 -e가 설정되고 명령이 a를 반환하더라도 -e 설정의 영향을받지 않습니다. 실패 상태. 복합 명령 또는 쉘 함수가 -e가 무시되는 컨텍스트에서 실행되는 동안 -e를 설정하면 복합 명령 또는 함수 호출을 포함하는 명령이 완료 될 때까지 해당 설정이 적용되지 않습니다.
-유
파라미터 확장을 수행 할 때 특수 파라미터 '@'또는 '*'이외의 설정되지 않은 변수 및 파라미터를 오류로 취급하십시오. 오류 메시지가 표준 오류에 기록되고 비 대화식 쉘이 종료됩니다.
필요하지 않은 경우 자유롭게 생략하십시오 :+${array[@]}
.
또한 [[
여기에서 연산자 를 사용하는 것이 중요합니다 [
.
$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
echo non-empty
else
echo empty
fi
$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty
@
반드시입니다. *
과 같은 배열 확장을 사용할 [ "${array[*]}" ]
수 있습니까? 여전히 [[
잘 작동합니다. 빈 문자열이 여러 개있는 배열에 대한이 두 가지의 동작은 약간 놀라운 것입니다. 모두 [ ${#array[*]} ]
와 [[ "${array[@]}" ]]
에 대한 거짓 array=()
과 array=('')
하지만에 대한 사실 array=('' '')
(두 개 이상의 빈 문자열). 하나 이상의 빈 문자열을 모두 true로 원하면을 사용할 수 있습니다 [ ${#array[@]} -gt 0 ]
. 당신이 그들 모두를 거짓으로 원한다면, 당신은 아마 //
그들을 밖으로 할 수 있습니다.
[ "${array[*]}" ]
있지만 그러한 표현에 빠지면 그것이 무엇을 이해하는지가 더 어려워집니다. 이후는 [...]
보간의 결과에 문자열의 관점에서 작동한다. 반대로 [[...]]
보간 된 것을 알 수 있습니다. 즉, 배열이 전달되었음을 알 수 있습니다. [[ ${array[@]} ]]
"배열이 비어 있지 않은지 확인"으로, [ "${array[*]}" ]
"모든 배열 요소의 보간 결과가 비어 있지 않은 문자열 인지 확인"으로 읽습니다 .
[ ${#array[*]} ]
, 아마도 [ "${array[*]}" ]
많은 요소에 대해 전자가 사실이기 때문에 아마도 의미했을 것입니다 . 요소 수는 항상 비어 있지 않은 문자열이기 때문입니다. 두 개의 요소가있는 후자에 대해서는 괄호 안의 표현식 ' '
이 비어 있지 않은 문자열로 확장됩니다 . 에 관해서는 [[ ${array[@]} ]]
, 그들은 두 요소의 배열이 비어 있지 않다고 생각합니다.
당신은 빈 배열을 검색하도록하려면 요소 처럼,arr=("" "")
등, 빈과 동일arr=()
모든 요소를 붙여넣고 결과 길이가 0인지 확인할 수 있습니다. (배열이 매우 클 수 있으면 배열 내용의 병합 사본을 작성하는 것은 성능에 이상적이지 않습니다. 그러나 그런 프로그램에 bash를 사용하지 않기를 바랍니다 ...)
그러나 "${arr[*]}"
의 첫 문자로 구분 된 요소로 확장됩니다 IFS
. 따라서 IFS를 저장 / 복원 IFS=''
하고이 작업을 수행해야 합니다. 그렇지 않으면 문자열 길이 == # 배열 요소 수-1 ( n
요소 배열에 n-1
구분 기호가 있음)을 확인해야합니다. 한 번에 하나씩 처리하려면 연결을 1만큼 채우는 것이 가장 쉽습니다.
arr=("" "")
## Assuming default non-empty IFS
## TODO: also check for ${#arr[@]} -eq 0
concat="${arr[*]} " # n-1 separators + 1 space + array elements
[[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
테스트 케이스 set -x
### a non-empty element
$ arr=("" "x")
+ arr=("" "x")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' x '
+ [[ 3 -ne 2 ]]
+ echo not empty array
not empty array
### 2 empty elements
$ arr=("" "")
+ arr=("" "")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' '
+ [[ 2 -ne 2 ]]
+ echo empty array
empty array
불행히도 이것은 실패합니다 arr=()
: [[ 1 -ne 0 ]]
. 따라서 실제로 빈 배열을 먼저 별도로 확인해야합니다.
또는IFS=''
. 아마도 서브 쉘을 사용하는 대신 IFS를 저장 / 복원하고 싶을 것입니다. 서브 쉘에서 쉽게 결과를 얻을 수 없기 때문입니다.
# inside a () subshell so we don't modify our own IFS
(IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
예:
$ arr=("" "")
$ (IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
+ IFS=
+ [[ -n '' ]]
+ echo empty array
empty array
않습니다 와 함께 작동 arr=()
- 그것은 여전히 빈 문자열입니다.
[[ "${arr[*]}" = *[![:space:]]* ]]
비공식적 이지만 적어도 하나의 비 WS 문자를 사용할 수 있기 때문에를 사용하기 시작했습니다 .
arr=(" ")
입니다.
제 경우 에는 공백이있을 수 있기 때문에 두 번째 대답으로 는 충분하지 않았습니다. 나는 함께했다 :
if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
echo "No options"
else
echo "Options found"
fi
echo | wc
쉘 내장을 사용하는 것에 비해 불필요하게 비효율적 인 것 같습니다.
[ ${#errors[@]} -eq 0 ];
공백 문제를 해결하기 위해 두 번째 답변을 수정할 수 있습니까? 또한 내장 기능을 선호합니다.
$#
숫자로 확장되고 이후에도 잘 작동합니다 opts+=("")
. 예를 들어, unset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
내가 얻을 2
. 작동하지 않는 예를 보여줄 수 있습니까?
opts=("")
은 같은 취급해야 opts=()
합니까? 그것은 빈 배열이 아니지만 빈 배열이나 빈 첫 번째 요소를 확인할 수 opts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
있습니다. 귀하의 현재 답변에는에 대한 "옵션 없음"이라고 표시되어 opts=("" "-foo")
있으며 이는 완전히 가짜이며 이는 해당 동작을 재현합니다. 당신은 수 [[ -z "${opts[*]}" ]]
I는 평면 문자열로 모든 배열 요소 보간 추측 -z
길이가 0이 아닌를 확인합니다. 첫 번째 요소를 검사하면 충분 -z "$opts"
합니다.
이중 괄호를 사용하는 것이 좋습니다.
if [[ !${array[@]} ]]
then
echo "Array is empty"
else
echo "Array is not empty"
fi
이중 괄호 : https://stackoverflow.com/questions/669452/is-preferable-over-in-bash
=
문자열 연산자입니다. 이 경우에는 잘 작동하지만-eq
대신 적절한 산술 연산자를 사용합니다 (-ge
또는-lt
등 으로 전환하려는 경우를 대비하여 ).