![별칭 있음](https://linux55.com/image/78343/%EB%B3%84%EC%B9%AD%20%EC%9E%88%EC%9D%8C.png)
배열 변수를 지원하는 Bourne과 같은 셸에서는 구문 분석을 사용하여 변수가 배열인지 확인할 수 있습니다.
아래의 모든 명령은 run 후에 실행됩니다 a=(1 2 3)
.
zsh
:
$ declare -p a
typeset -a a
a=( 1 2 3 )
bash
:
$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'
ksh93
:
$ typeset -p a
typeset -a a=(1 2 3)
pdksh
그리고 그 파생물:
$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3
yash
:
$ typeset -p a
a=('1' '2' '3')
typeset a
다음의 예 bash
:
if declare -p var 2>/dev/null | grep -q 'declare -a'; then
echo array variable
fi
이 방법은 너무 많은 작업이 필요하며 서브셸을 생성해야 합니다. =~
in 과 같은 다른 쉘 내장 기능을 사용하면 [[ ... ]]
서브쉘이 필요하지 않지만 여전히 너무 복잡합니다.
이 작업을 수행하는 더 쉬운 방법이 있습니까?
답변1
나는 당신이 할 수 있다고 생각하지 않으며 실제로 아무런 차이가 없다고 생각합니다.
unset a
a=x
echo "${a[0]-not array}"
x
ksh93
이는 및 에서 동일한 작업을 수행합니다 bash
. 가능할 것 같다모두변수는 이러한 셸의 배열이거나 적어도 특별한 속성이 할당되지 않은 일반 변수이지만 많이 확인하지는 않았습니다.
매뉴얼 bash
에서는 할당을 사용할 때 배열과 문자열 변수의 다양한 동작에 대해 설명 +=
하지만 배열은 다음 상황에서만 다르게 동작한다는 것을 방지하고 명시합니다.화합물컨텍스트를 할당합니다.
또한 값이 첨자에 할당되면 변수가 배열로 처리되며 빈 문자열의 가능성이 명시적으로 포함되어 있음을 나타냅니다. 위에서 정규 할당으로 인해 반드시 첨자가 할당된다는 것을 알 수 있습니다. 따라서 모든 것이 배열인 것 같습니다.
실제로 다음을 사용할 수 있습니다.
[ 1 = "${a[0]+${#a[@]}}" ] && echo not array
...값이 0인 단일 첨자만 할당된 컬렉션 변수를 명확하게 찾아냅니다.
답변2
그렇다면 실제로 중간 부분만 원하고 declare -p
주변 부분은 원하지 않는다는 건가요?
다음과 같은 매크로를 작성할 수 있습니다.
readonly VARTYPE='{ read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
} <<<'
이렇게 하면 다음을 수행할 수 있습니다.
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(함수 로컬 변수에 사용하려는 경우 함수만으로는 작동하지 않습니다).
별칭 있음
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
답변3
zsh에서
zsh% a=(1 2 3) s=1
zsh% [[ ${(t)a} == *array* ]] && echo array
array
zsh% [[ ${(t)s} == *array* ]] && echo array
zsh%
답변4
~을 위한세게 때리다, 이는 약간의 해킹입니다(문서화되어 있지만). 다음을 typeset
사용하여 "배열" 속성을 제거해 보세요.
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
zsh
( 배열을 스칼라로 변환할 수 있는 와 에서는 이 작업을 수행할 수 없습니다 . bash
이 작업은 명시적으로 금지됩니다.)
그래서:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
또는 함수의 끝에 있는 경고에 유의하세요.
function typeof() {
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
}
(bash-4.2 이상) 의 사용에 유의하세요. 이는 (syn. ) 이 확인하려는 값처럼 동작하거나 손상되지 않도록 typeset -g
함수에 필요합니다 . 이는 또한 함수 "변수" 유형을 처리하지 않으므로 필요한 경우 다른 분기 테스트를 추가할 수 있습니다.typeset
declare
local
typeset -f
또 다른 (거의 완전한) 옵션은 다음을 사용하는 것입니다.
${!name[*]}
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
그러나 작은 문제가 있습니다. 인덱스가 0인 단일 배열은 위의 두 가지 조건을 충족합니다. mikeserv도 이것을 인용했는데, bash에는 실제로 엄격한 차이가 없습니다. 그 중 일부(변경 로그를 확인하면)는 ksh와 ${name[*]}
비배열에서 작동하는 방식과의 호환성 때문일 수 있습니다.${name[@]}
그래서부분의해결책은 다음과 같습니다.
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
나는 과거에 이 방법의 변형을 사용해 왔습니다.
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
그러나 이를 위해서는 서브셸도 필요합니다.
유용할 수 있는 또 다른 기술은 다음과 같습니다 compgen
.
compgen -A arrayvar
이것은 모든 인덱스 배열을 나열하지만 연관 배열은 (bash-4.4까지) 특별하게 처리되지 않고 일반 변수( compgen -A variable
) 로 표시됩니다.