어레이에 대한 테스트 셸 지원

어레이에 대한 테스트 셸 지원

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모든 Bourne 유사 쉘은 --versionksh가 인터럽트할 때 긴 옵션을 인식한다고 가정합니다.예를 들어.)

나는 무인으로 병합할 수 있는 간단한 테스트를 찾고 있습니다.용법스크립트의 시작 부분에서는 이전 섹션을 호출하기도 합니다.

답변1

Bourne과 같은 쉘( , , 또는 csh지원 tcsh배열 과 같은 다른 많은 쉘 rc)로 제한하고 싶지만 Bourne과 같은 쉘과도 호환되는 스크립트를 작성하는 것은 완전히 다른 인터프리터이기 때문에 호환되지 않기 때문에 까다롭고 종종 무의미하다고 가정해 보겠습니다. 언어), 구현 간에는 상당한 차이가 있다는 점에 유의하세요.esfish

배열을 지원하는 Bourne과 유사한 쉘(지원이 추가된 순서대로)은 다음과 같습니다.

  • ksh88(원래 ksh의 마지막 진화인 ksh88은 최초의 배열 구현으로 ksh대부분의 전통적인 상용 Unices에 여전히 존재하며 그 기반이기도 합니다 sh.)

    • 배열은 1차원입니다.
    • 배열이 or로 시작하지 않는다고 보장할 수 없는 경우 배열을 set -A array foo baror로 정의하세요.set -A array -- "$var" ...$var-+
    • 배열 인덱스는 에서 시작됩니다 0.
    • 개별 배열 요소는 로 지정됩니다 a[1]=value.
    • 배열이 드물다. 이는 설정되지 않은 a[5]=foo경우에도 작동하며 설정되지 않은 상태로 유지됩니다.a[0,1,2,3,4]
    • ${a[5]}인덱스 5의 요소에 액세스합니다(배열이 희박한 경우 반드시 6번째 요소일 필요는 없음). 임의의 산술 표현식 이 있을 수 5있습니다.
    • 배열 크기와 첨자는 제한됩니다(최대 4096개).
    • ${#a[@]}배열의 지정된 요소 수입니다(지정된 최대 인덱스가 아님).
    • 할당된 첨자의 목록을 알 수 있는 방법은 없습니다(4096개 요소에 대한 개별 테스트를 사용하는 것 외에는 [[ -n "${a[i]+set}" ]]).
    • $a동일합니다 ${a[0]}. 즉, 배열은 추가 값을 제공하여 어떤 방식으로든 스칼라 변수를 확장합니다.
  • pdkshksh및 파생물(일부 BSD, 때로는 여러 개의 BSD의 기반이었으며 shksh93 소스 코드가 출시될 때까지 유일한 오픈 소스 ksh 구현이었습니다):

    주로 좋아 ksh88하지만 참고하세요:

    • 일부 이전 구현에서는 이를 지원하지 않습니다 set -A array -- foo bar( --여기서는 필요하지 않습니다).
    • ${#a[@]}할당된 가장 큰 인덱스에 1을 더한 인덱스입니다. ( a[1000]=1; echo "${#a[@]}"배열에 요소가 하나만 있어도 1001이 출력됩니다.
    • 최신 버전에서는 배열 크기가 더 이상 제한되지 않습니다(정수 크기 제외).
    • 의 최신 버전에는 할당된 인덱스 목록을 얻기 위해 mksh에서 영감을 받은 추가 연산자 bash또는 할당 la 와 같은 연산자 ksh93가 있습니다.zsha=(x y)a+=(z)${!a[@]}
  • zsh. 어레이는 일반적으로 더 잘 설계되었으며 zsh어레이를 최대한 활용합니다. 보시다시피kshcsh1991년에 출시된 zsh 2.0, 디자인 영감은 ksh가 아닌 tcsh에서 나옵니다. 이는 ksh배열과 일부 유사점을 공유하지만 중요한 차이점도 있습니다.

    • ksh인덱싱은 Bourne 배열(위치 매개변수 $@, zsh$argv 배열로도 노출됨) 및 csh배열 과 일치하여 0 대신 1에서 시작합니다(시뮬레이션 제외 ).
    • 일반/스칼라 변수와는 다른 유형입니다. 일반적으로 예상하는 것처럼 연산자는 다르게 적용됩니다. $a배열과 달리 ${a[0]}배열의 비어 있지 않은 요소로 확장됩니다( "${a[@]}"in 과 같은 모든 요소에 대해 ksh).
    • 희소 배열이 아닌 일반 배열입니다. a[5]=1유효하지만 할당되지 않은 경우 1~4의 모든 요소가 빈 문자열로 할당됩니다. 따라서 ${#a[@]}( ksh 의 인덱스 0에 있는 요소와 동일한 크기 ${#a})는 배열의 요소 수입니다.그리고지정된 최대 인덱스입니다.
    • 연관 배열을 지원합니다.
    • 배열 작업을 위한 수많은 연산자가 지원되며 여기에 나열하기에는 너무 많습니다.
    • a=(x y)로 정의 된 배열 set -A a x y과의 호환성에도 사용 가능 ksh하지만 ksh 에뮬레이션을 제외하고는 지원되지 않습니다(zsh 에뮬레이션에서는 필요하지 않음) set -A a -- x y.--
  • ksh93. (최신 버전은 여기에 설명되어 있습니다). ksh93원작자가 다시 쓴 는 오랫동안 고려되어 왔습니다 .ksh실험적인FOSS로 출시된 이후 이제 점점 더 많은 시스템에서 찾을 수 있습니다. 예를 들어, 이는 ( POSIX 쉘이 여전히 기반으로 하고 있는 /bin/shBourne 쉘을 대체함 ) 및 입니다 . 해당 배열은 ksh88의 배열을 확장하고 향상시킵니다./usr/xpg4/bin/shksh88kshSolaris 11

    • 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)희소 배열은 구문을 사용하여 한 번 정의할 수 있습니다 .
    • 최대 배열 인덱스가 4,194,303으로 증가했습니다.
    • 같은 정도는 아니지만 zsh배열에서 작동하는 많은 수의 연산자도 지원합니다.
    • "${!a[@]}"배열 인덱스 목록을 검색합니다.
    • 연관 배열은 별도의 유형으로도 지원됩니다.
  • bash. bashGNU 프로젝트의 쉘입니다. sh최신 버전의 OS/X 및 일부 GNU/Linux 배포판에서 사용됩니다 . bash배열은 주로 ksh88및 의 일부 기능을 사용하여 배열을 시뮬레이션합니다.ksh93zsh

    • 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 value5번째 요소를 미리 할당하지 않으면 수정이 실패 합니다 .
    • 배열의 요소 수는 ${a[#]}목록 ${#a[@]}에 있는 요소의 크기입니다.
    • 배열은 별도의 유형입니다. a=("$a")요소를 추가하거나 수정하려면 먼저 스칼라 변수를 배열로 다시 정의 해야 합니다 .
    • "$array"있는 그대로 배열의 모든 요소로 확장하므로 다른 쉘보다 사용하기가 더 쉽습니다(배열의 요소를 인수로 사용하여 호출되는 ksh/bash/zsh와 비교 cmd "$array"; 꺼져 있지만 빈 요소를 제거합니다). .cmdcmd "${array[@]}"zshcmd $array
    • 로 호출하면 배열이 지원되지 않습니다 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)를 사용하여 배열 요소 수( in $REPLY)를 가져오거나 배열을 전체적으로 설정하거나 단일 요소를 할당할 수 있습니다.

아마도 노력할 가치가 없을 것입니다. perlBourne/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희소 배열을 만들려고 하지 않는 한 다음을 일관되게 사용할 수 있습니다.ksh88pdksh

  • a[0]=foo
  • a=(foo bar)(하지만 a=())
  • "${a[#]}", "${a[@]}","${a[0]}"

가 있는 기능에서 사용자는 여전히 일반적 emulate -L ksh으로 zshzsh 방식으로 배열을 사용합니다.

답변2

다음을 사용하여 배열 구문을 시도해 볼 수 있습니다 eval.

is_array_support() (
  eval 'a=(1)'
) >/dev/null 2>&1

if is_array_support; then
  echo support
else
  echo not
fi

관련 정보