명령 줄에서 로컬 Bourne과 같은 쉘에서 어레이 지원을 간결하게 테스트하는 방법이 있습니까?
이것은 항상 가능합니다 :
$ arr=(0 1 2 3);if [ "${arr[2]}" != 2 ];then echo "No array support";fi
또는 $SHELL
쉘 버전 테스트 및 테스트 :
$ eval $(echo "$SHELL --version") | grep version
그런 다음 액세스 권한이 있다고 가정하고 매뉴얼 페이지를 읽습니다. (심지어 거기에서 편지를 쓰고 /bin/bash
, 나는 가정하고 모든 본쉘 긴 옵션을 인정 --version
, KSH에 대한 그 휴식 예를 들어 .)
스크립트 시작시 또는 호출 전에 사용 섹션에 무인으로 통합 할 수있는 간단한 테스트를 찾고 있습니다.
답변
당신은 본쉘 (다른 많은 조개 등을 제한 할 가정 csh
, tcsh
, rc
, es
또는 fish
지원 배열하지만 껍질 같은 Bourne 씨에 동시에 호환 스크립트를 작성하고 완전히 다른 및 통역과 마찬가지로 사람들은 까다 롭고 일반적으로 무의미 호환되지 않는 언어), 구현 간에는 상당한 차이가 있습니다.
배열을 지원하는 Bourne과 같은 쉘은 다음과 같습니다.
-
ksh88
(배열을 구현하는 최초의 하나가, ksh88 여전히 같은 발견ksh
은 또한의 기초가 어디 대부분 기존의 상용 유닉스에서sh
)- 배열은 1 차원입니다
- 배열로 정의되어 있습니다
set -A array foo bar
또는set -A array -- "$var" ...
당신은 보장 할 수없는 경우 그$var
이 시작되지 않습니다-
또는+
. - 배열 인덱스는에서 시작
0
합니다. - 개별 배열 요소는로 지정됩니다
a[1]=value
. - 배열이 드물다. 즉
a[5]=foo
경우에도 작동a[0,1,2,3,4]
설정되지 않은 및 해제를 떠날 것이다. ${a[5]}
indice 5의 요소에 액세스하기 위해 (배열이 드문 경우 반드시 여섯 번째 요소는 아닙니다). 는5
산술 표현식이있을 수있다.- 배열 크기와 아래 첨자는 4096으로 제한됩니다.
${#a[@]}
배열에서 할당 된 요소의 수입니다 (가장 큰 할당 된 지표는 아님).- 지정된 첨자 목록을 알 수있는 방법은 없습니다 (4096 개 요소를 개별적으로 테스트하는 것 제외
[[ -n "${a[i]+set}" ]]
). $a
와 동일합니다${a[0]}
. 즉, 배열은 스칼라 변수에 추가 값을 제공하여 확장합니다.
-
pdksh
그리고 파생 상품 (이것은ksh
때로는sh
여러 BSD 의 기초이며 ksh93 소스가 해제되기 전에 유일한 오픈 소스 ksh 구현이었습니다) :주로 좋아
ksh88
하지만 참고하십시오 :- 일부 오래된 구현은을 지원하지 않았습니다
set -A array -- foo bar
(--
필요하지 않았습니다). ${#a[@]}
가장 큰 배정 된 지표의 지수에 1을 더한 것입니다. (a[1000]=1; echo "${#a[@]}"
배열에 요소가 하나만 있어도 1001을 출력합니다.- 최신 버전에서는 배열 크기가 더 이상 제한되지 않습니다 (정수 크기 제외).
- 최근 버전
mksh
에서 영감을 몇 가지 추가 연산자를 가지고bash
,ksh93
또는zsh
라 과제처럼a=(x y)
,a+=(z)
,${!a[@]}
할당 된 인덱스의 목록을 얻을 수 있습니다.
- 일부 오래된 구현은을 지원하지 않았습니다
-
zsh
.zsh
배열은 일반적으로 더 나은 디자인과 최고의 가지고 있습니다ksh
및csh
배열을. 그것들은 비슷ksh
하지만 큰 차이점이 있습니다.- 인덱스는 0이 아닌 1에서 시작합니다 (
ksh
에뮬레이션 제외 ). Bourne 배열 (zsh
$ argv 배열로 표시 되는 위치 매개 변수 $ @ ) 및csh
배열 과 일치 합니다. - 그것들은 정규 / 스칼라 변수와는 별개의 유형입니다. 운영자는 일반적으로 기대하는 것처럼 다르게 적용됩니다.
$a
는 같지${a[0]}
않지만 배열의 비어 있지 않은 요소로 확장됩니다 ("${a[@]}"
에서와 같은 모든 요소에 대해ksh
). - 그것들은 희소 배열이 아닌 일반 배열입니다.
a[5]=1
작동하지만 1에서 4까지의 모든 요소가 할당되지 않은 경우 빈 문자열을 할당합니다. 따라서${#a[@]}
(${#a}
ksh에서 indice 0의 요소 크기 와 동일 )는 배열의 요소 수 와 가장 큰 할당 된 indice입니다. - 연관 배열이 지원됩니다.
- 배열로 작업하기위한 수많은 연산자가 지원되며 여기에 나열하기에는 너무 큽니다.
- 로 정의 된 배열
a=(x y)
.set -A a x y
또한 작동하지만set -A a -- x y
ksh 에뮬레이션이 아닌 경우 지원되지 않습니다 (--
zsh 에뮬레이션에는 필요하지 않음).
- 인덱스는 0이 아닌 1에서 시작합니다 (
-
ksh93
. (여기서는 최신 버전을 설명합니다). FOSS로 출시 된 지금은ksh93
오랫동안 실험으로 간주 된 실험 이 점점 더 많은 시스템에서 발견 될 수 있습니다. 예를 들어,/bin/sh
(Bourne 쉘을 대체/usr/xpg4/bin/sh
한 POSIX 쉘은 여전히을 기반으로합니다ksh88
) 및ksh
의Solaris 11
입니다. 그 배열은 ksh88을 확장하고 향상시킵니다.a=(x y)
는 배열을 정의하는 데 사용될 수 있지만a=(...)
복합 변수 (a=(foo=bar bar=baz)
) 를 정의하는 데에도 사용 되므로a=()
모호하며 배열이 아닌 복합 변수를 선언합니다.- 배열은 다차원 (
a=((0 1) (0 2))
)이며 배열 요소는 복합 변수 (a=((a b) (c=d d=f)); echo "${a[1].c}"
) 일 수도 있습니다 . a=([2]=foo [5]=bar)
구문은 한 번에 스파 스 배열을 정의 할 수 있습니다.- 크기 제한이 해제되었습니다.
- 의 범위는
zsh
아니지만 배열을 조작하는 데 지원되는 많은 연산자가 있습니다. "${!a[@]}"
배열 인덱스 목록을 검색합니다.- 연관 배열도 별도의 유형으로 지원됩니다.
-
bash
.bash
GNU 프로젝트의 쉘입니다. 그것은으로 사용되는sh
OS / X 및 일부 GNU / Linux 배포판의 최신 버전에.bash
배열은 주로 및의ksh88
일부 기능이있는 배열을 에뮬레이션 합니다 .ksh93
zsh
a=(x y)
지원됩니다. 지원set -A a x y
되지 않습니다 .a=()
빈 배열을 만듭니다 (에 복합 변수 없음bash
)."${!a[@]}"
지수 목록.a=([foo]=bar)
ksh93
및 에서 제공되는 구문뿐만 아니라 다른 구문도 지원합니다zsh
.- 최신
bash
버전은 또한 연관 배열을 별도의 유형으로 지원합니다.
-
yash
. 비교적 최신의 깨끗한 멀티 바이트 인식 POSIX sh 구현입니다. 널리 사용되지 않습니다. 배열은 다음과 비슷한 또 다른 깨끗한 API입니다.zsh
- 배열이 희박하지 않습니다
- 배열 인덱스는 1에서 시작
- 로 정의 및 선언
a=(var value)
array
내장으로 삽입, 삭제 또는 수정 된 요소array -s a 5 value
해당 요소가 사전에 지정되지 않은 경우 5 번째 요소 를 수정하면 실패합니다.- 배열의 요소 수는
${a[#]}
,${#a[@]}
리스트와 요소의 크기 인. - 배열은 별도의 유형입니다.
a=("$a")
요소를 추가하거나 수정하기 전에 스칼라 변수를 배열로 재정의 해야 합니다. - 로 호출되면 배열이 지원되지 않습니다
sh
.
따라서 배열 지원을 감지하는 것을 볼 수 있습니다.
if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
) > /dev/null 2>&1
then
array_supported=true
else
array_supported=false
fi
그 배열을 사용할 수있을만큼 충분하지 않습니다. 배열을 전체 및 개별 요소로 할당하기 위해 래퍼 명령을 정의하고 희소 배열을 만들지 않도록해야합니다.
처럼
unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
set -A a -- a b
case ${a[0]}${a[1]} in
--) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=0;;
a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=1;;
--a) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
esac
elif (eval 'a[5]=x') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() {
eval "
$1=(\${$1+\"\${$1[@]}"'"})
while [ "$(($2))" -ge "${'"$1"'[#]}" ]; do
array -i "$1" "$2" ""
done'
array -s -- "$1" "$((1+$2))" "$3"
}
array_elements() { eval "REPLY=\${$1[#]}"; }
first_indice=1
else
echo >&2 "Array not supported"
fi
그리고 당신은 배열을 가진 요소에 액세스 "${a[$first_indice+n]}"
하여, 전체 목록 "${a[@]}"
과 래퍼 함수를 사용 ( array_elements
, set_array
, set_array_element
) (에서 배열의 요소 수를 얻기 위해 $REPLY
), 전체 또는 할당 개별 요소로 배열을 설정합니다.
노력할만한 가치가 없을 것입니다. perl
Bourne / POSIX 셸 배열을 사용 하거나 제한합니다 "$@"
.
내부적으로 배열을 사용하는 함수를 정의하기 위해 사용자의 대화식 쉘에서 일부 파일을 소싱하려는 의도가 있다면 유용한 몇 가지 참고 사항이 있습니다.
로컬 범위 (함수 또는 익명 함수)의 배열 zsh
과 유사하게 배열을 구성 할 수 있습니다 ksh
.
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
또한 다음을 사용하여 에뮬레이션 할 수 있습니다 ksh
( ksh
배열 및 기타 여러 영역과의 호환성 향상 ).
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
이를 염두에두고 파생 버전의 이전 버전과 이전 버전에 대한 지원을 기꺼이 포기 yash
하고 희소 배열을 만들지 않는 한 일관성있게 사용할 수 있어야합니다.ksh88
pdksh
a[0]=foo
a=(foo bar)
(하지만 아닙니다a=()
)"${a[#]}"
,"${a[@]}"
,"${a[0]}"
이 이러한 기능에 emulate -L ksh
그동안, zsh
사용자가 정상적으로 그 / 그녀의 배열 zsh을 방법을 사용하여.
답변
eval
배열 구문을 시도하는 데 사용할 수 있습니다 .
is_array_support() (
eval 'a=(1)'
) >/dev/null 2>&1
if is_array_support; then
echo support
else
echo not
fi