Unix Bourne Shell의 배열

Unix Bourne Shell의 배열

/bin/shBourne 쉘( )에서 배열을 사용 하려고 합니다 . 배열 요소를 초기화하는 방법은 다음과 같습니다.

arr=(1 2 3)

하지만 오류가 발생했습니다.

syntax error at line 8: `arr=' unexpected

이제 이 구문에 대해 제가 찾은 게시물에서는 에 대한 것이라고 나와 있지만 bashBourne 쉘에 대한 별도의 구문을 찾을 수 없습니다. 구문이 /bin/sh동일합니까?

답변1

/bin/sh요즘 시스템에는 Bourne 쉘이 거의 없습니다(Bourne 쉘을 포함하는 마지막 주요 시스템 중 하나인 Solaris도 이제 Solaris 11에서 /bin/sh를 POSIX sh로 전환했습니다). /bin/sh1970년대 초반 톰슨 포탄입니다. 1979년에는 Bourne 쉘이 Unix V7에서 이를 대체했습니다.

/bin/sh수년 동안 그것은 Bourne 쉘(또는 BSD에서 무료로 재구현된 Almquist 쉘)이었습니다.

요즘에는 ksh88 언어의 하위 집합(및 Bourne 쉘 언어의 상위 집합이지만 일부 비호환성)을 기반으로 하는 POSIX 언어용 인터프리터 또는 기타 인터프리터가 /bin/sh더 일반적 입니다.sh

Bourne 쉘 또는 POSIX sh 언어 사양에서는 배열이 지원되지 않습니다. 또는 위치 매개변수( $1, $2, $@, 따라서 각 함수에도 배열이 있음)라는 하나의 배열만 있습니다.

ksh88에는 를 사용하여 설정한 배열이 있지만 set -A구문이 어색하고 사용하기가 쉽지 않기 때문에 POSIX sh에서는 지정되지 않습니다.

배열/목록 변수가 있는 다른 쉘에는 다음이 포함됩니다: csh/ tcsh, rc, es, bash(대부분 ksh93 방식으로 ksh 구문 복사), yash, zsh, fish각각 다른 구문을 사용함( rc향후 Unix 후속 쉘 fishzsh가장 일관된 쉘) ...

표준에서 sh(Bourne 쉘의 최신 버전에서도 작동함):

set '1st element' 2 3 # setting the array

set -- "$@" more # adding elements to the end of the array

shift 2 # removing elements (here 2) from the beginning of the array

printf '<%s>\n' "$@" # passing all the elements of the $@ array 
                     # as arguments to a command

for i do # looping over the  elements of the $@ array ($1, $2...)
  printf 'Looping over "%s"\n' "$i"
done

printf '%s\n' "$1" # accessing individual element of the array.
                   # up to the 9th only with the Bourne shell though
                   # (only the Bourne shell), and note that you need
                   # the braces (as in "${10}") past the 9th in other
                   # shells (except zsh, when not in sh emulation and
                   # most ash-based shells).

printf '%s\n' "$# elements in the array"

printf '%s\n' "$*" # join the elements of the array with the 
                   # first character (byte in some implementations)
                   # of $IFS (not in the Bourne shell where it's on
                   # space instead regardless of the value of $IFS)

(Bourne 셸 및 ksh88에서는 이것이 작동하려면 $IFS공백 문자가 포함되어야 하며 "$@"(버그) Bourne 셸에서는 위 요소에 액세스할 수 없습니다 $9( ${10}작동하지 않지만 여전히 실행하거나 shift 1; echo "$9"반복할 수 있습니다). ).

답변2

다른 사람들이 말했듯이 Bourne Shell은 그렇지 않습니다.진짜정렬.

그러나 수행해야 하는 작업에 따라 문자열을 구분하는 것만으로도 충분합니다.

sentence="I don't need arrays because I can use delimited strings"
for word in $sentence
do
  printf '%s\n' "$word"
done

일반적인 구분 기호(공백, 탭 및 줄 바꿈)가 충분하지 않은 경우 다음을 설정할 수 있습니다.IFS루프 앞에 원하는 구분 기호.

프로그래밍 방식으로 배열을 작성해야 하는 경우 구분된 문자열을 작성하면 됩니다.

답변3

일반적인 Bourne 쉘에는 배열이 없습니다. 다음을 사용하여 배열을 만들고 반복할 수 있습니다.

#!/bin/sh
# ARRAY.sh: example usage of arrays in Bourne Shell

array_traverse()
{
    for i in $(seq 1 $2)
    do
    current_value=$1$i
    echo $(eval echo \$$current_value)
    done
    return 1
}

ARRAY_1=one
ARRAY_2=two
ARRAY_3=333
array_traverse ARRAY_ 3

배열을 사용하기 위해 어떤 방법을 선택하든 sh항상 번거롭습니다. 가능하다면 매우 제한된 플랫폼에 제한되어 있거나 무언가를 배우고 싶은 경우가 아니면 Python다른 언어를 사용하는 것을 고려해 보십시오.Perl

답변4

대시로 배열을 시뮬레이션하는 방법(배열의 임의 크기에 적응할 수 있음): (이 seq명령을 사용하려면 IFS" "(공백 = 기본값)로 설정해야 합니다. 이 상황을 피하기 위해 사용하거나 반복 while ... do ...할 수 있습니다. 코드의 기능을 더 잘 설명하기 위해 범위 내에서 do ... while ...유지하겠습니다 .)seq

#!/bin/sh

## The following functions implement vectors (arrays) operations in dash:
## Definition of a vector <v>:
##      v_0 - variable that stores the number of elements of the vector
##      v_1..v_n, where n=v_0 - variables that store the values of the vector elements

VectorAddElementNext () {
# Vector Add Element Next
# Adds the string contained in variable $2 in the next element position (vector length + 1) in vector $1

    local elem_value
    local vector_length
    local elem_name

    eval elem_value=\"\$$2\"
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    vector_length=$(( vector_length + 1 ))
    elem_name=$1_$vector_length

    eval $elem_name=\"\$elem_value\"
    eval $1_0=$vector_length
}

VectorAddElementDVNext () {
# Vector Add Element Direct Value Next
# Adds the string $2 in the next element position (vector length + 1) in vector $1

    local elem_value
    local vector_length
    local elem_name

    eval elem_value="$2"
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    vector_length=$(( vector_length + 1 ))
    elem_name=$1_$vector_length

    eval $elem_name=\"\$elem_value\"
    eval $1_0=$vector_length
}

VectorAddElement () {
# Vector Add Element
# Adds the string contained in the variable $3 in the position contained in $2 (variable or direct value) in the vector $1

    local elem_value
    local elem_position
    local vector_length
    local elem_name

    eval elem_value=\"\$$3\"
    elem_position=$(($2))
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    if [ $elem_position -ge $vector_length ]; then
        vector_length=$elem_position
    fi

    elem_name=$1_$elem_position

    eval $elem_name=\"\$elem_value\"
    if [ ! $elem_position -eq 0 ]; then
        eval $1_0=$vector_length
    fi
}

VectorAddElementDV () {
# Vector Add Element
# Adds the string $3 in the position $2 (variable or direct value) in the vector $1

    local elem_value
    local elem_position
    local vector_length
    local elem_name

    eval elem_value="$3"
    elem_position=$(($2))
    eval vector_length=\$$1\_0
    if [ -z "$vector_length" ]; then
        vector_length=$((0))
    fi

    if [ $elem_position -ge $vector_length ]; then
        vector_length=$elem_position
    fi

    elem_name=$1_$elem_position

    eval $elem_name=\"\$elem_value\"
    if [ ! $elem_position -eq 0 ]; then
        eval $1_0=$vector_length
    fi
}

VectorPrint () {
# Vector Print
# Prints all the elements names and values of the vector $1 on sepparate lines

    local vector_length

    vector_length=$(($1_0))
    if [ "$vector_length" = "0" ]; then
        echo "Vector \"$1\" is empty!"
    else
        echo "Vector \"$1\":"
        for i in $(seq 1 $vector_length); do
            eval echo \"[$i]: \\\"\$$1\_$i\\\"\"
            ###OR: eval printf \'\%s\\\n\' \"[\$i]: \\\"\$$1\_$i\\\"\"
        done
    fi
}

VectorDestroy () {
# Vector Destroy
# Empties all the elements values of the vector $1

    local vector_length

    vector_length=$(($1_0))
    if [ ! "$vector_length" = "0" ]; then
        for i in $(seq 1 $vector_length); do
            unset $1_$i
        done
        unset $1_0
    fi
}

##################
### MAIN START ###
##################

## Setting vector 'params' with all the parameters received by the script:
for i in $(seq 1 $#); do
    eval param="\${$i}"
    VectorAddElementNext params param
done

# Printing the vector 'params':
VectorPrint params

read temp

## Setting vector 'params2' with the elements of the vector 'params' in reversed order:
if [ -n "$params_0" ]; then
    for i in $(seq 1 $params_0); do
        count=$((params_0-i+1))
        VectorAddElement params2 count params_$i
    done
fi

# Printing the vector 'params2':
VectorPrint params2

read temp

## Getting the values of 'params2'`s elements and printing them:
if [ -n "$params2_0" ]; then
    echo "Printing the elements of the vector 'params2':"
    for i in $(seq 1 $params2_0); do
        eval current_elem_value=\"\$params2\_$i\"
        echo "params2_$i=\"$current_elem_value\""
    done
else
    echo "Vector 'params2' is empty!"
fi

read temp

## Creating a two dimensional array ('a'):
for i in $(seq 1 10); do
    VectorAddElement a 0 i
    for j in $(seq 1 8); do
        value=$(( 8 * ( i - 1 ) + j ))
        VectorAddElementDV a_$i $j $value
    done
done

## Manually printing the two dimensional array ('a'):
echo "Printing the two-dimensional array 'a':"
if [ -n "$a_0" ]; then
    for i in $(seq 1 $a_0); do
        eval current_vector_lenght=\$a\_$i\_0
        if [ -n "$current_vector_lenght" ]; then
            for j in $(seq 1 $current_vector_lenght); do
                eval value=\"\$a\_$i\_$j\"
                printf "$value "
            done
        fi
        printf "\n"
    done
fi

################
### MAIN END ###
################

관련 정보