Bourne shell ( /bin/sh
) 에서 배열을 사용하려고합니다 . 배열 요소를 초기화하는 방법은 다음과 같습니다.
arr=(1 2 3)
그러나 오류가 발생했습니다.
syntax error at line 8: `arr=' unexpected
이제이 구문을 찾은 게시물은에 bash
대한 것인데 Bourne 쉘에 대한 별도의 구문을 찾을 수 없습니다. 구문도 동일 /bin/sh
하게 적용됩니까?
Bourne shell ( /bin/sh
) 에서 배열을 사용하려고합니다 . 배열 요소를 초기화하는 방법은 다음과 같습니다.
arr=(1 2 3)
그러나 오류가 발생했습니다.
syntax error at line 8: `arr=' unexpected
이제이 구문을 찾은 게시물은에 bash
대한 것인데 Bourne 쉘에 대한 별도의 구문을 찾을 수 없습니다. 구문도 동일 /bin/sh
하게 적용됩니까?
답변:
/bin/sh
요즘은 모든 시스템에서 Bourne 쉘이 될 수는 없습니다 (Solaris 11에서 / bin / sh를 포함하여 마지막으로 주요 시스템 중 하나였던 Solaris조차도). /bin/sh
70 년대 초의 톰슨 껍질이었습니다. Bourne 쉘은 1979 년 Unix V7에서이를 대체했습니다.
/bin/sh
그 후 수년 동안 Bourne 쉘 (또는 Almquist 쉘, BSD에서 무료로 다시 구현)이었습니다.
요즘 /bin/sh
은 POSIX sh
언어 의 통역사 또는 다른 언어로, ksh88 언어의 하위 세트 (및 일부 비 호환성을 가진 Bourne 쉘 언어의 상위 세트)를 기반으로합니다.
Bourne 쉘 또는 POSIX sh 언어 사양은 배열을 지원하지 않습니다. 또는 오히려 그들은 단지 하나 개의 배열을 가지고 : 위치 매개 변수 ( $1
, $2
, $@
, 기능마다 하나 개의 배열을 잘 참조).
ksh88에는으로 설정 한 배열이 set -A
있지만 구문이 까다 롭고 사용할 수 없으므로 POSIX sh에 지정되지 않았습니다.
어레이 /리스트 변수와 다른 쉘을 포함한다 : csh
/ tcsh
, rc
, es
, bash
(주로 KSH 구문에게 ksh93의 방법을 복사 함), yash
, zsh
, fish
다른 구문 (각 rc
유닉스하려면-일 후에 후속의 쉘 fish
과 zsh
가장 부합되는 그들) ...
기본적으로 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.
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"
이상 또는 루프 그들)).
"$@"
배열 같은 역할 (의 배열과 같은 csh
, rc
, zsh
, fish
, yash
, 그것은 더 ...)을 콘 / bash는 정말 배열 아니다 "배열"하지만 일부 키가 양의 정수로 제한되는 연관 배열 형식 (배열 및 "$ @"이있는 다른 모든 쉘에서와 같이 1 대신 0부터 시작하는 인덱스도 있음). 슬라이싱을 지원하는 쉘은 $ @를 똑같이 슬라이스 할 수 있습니다 ( "$ @"를 슬라이스 할 때 ksh93 / bash가 위치 매개 변수에 $ 0를 어색하게 추가 함).
일반 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
당신은 매우 제한된 플랫폼과 붙어 또는 뭔가를 배울하려는 경우가 아니면 할 수 있습니다.
$(...)
구문 이 없습니다 . 따라서 실제로 Bourne 쉘이 있어야합니다. Solaris 10 또는 그 이전에 있습니까? 기회가 없을 수도 seq
있습니다. Solaris 10 및 이전 버전에서는 / usr / xpg4 / bin / sh가 sh
Bourne 쉘 대신 표준을 갖기를 원합니다 . seq
그 방법을 사용 하는 것도 좋지 않습니다.
seq
그런 식으로 사용 하는 것이 좋지 않습니까?
$(...)
이상 `
하지만, 영업 이익의는 /bin/sh
아마 Bourne 쉘이 아닌 POSIX 쉘입니다. 옆 seq
하 표준 명령이없는 $(seq 100)
메모리의 전체 출력을 저장하는 수단, 및 그 수단은 개행 함유 $ IFS의 현재 값에 의존 및 숫자를 포함하지. 사용 i=1; while [ "$i" -le 100 ]; ...; i=$(($i + 1)); done
하는 것이 가장 좋습니다 (Bourne 쉘에서도 작동하지 않지만).
/bin/sh
나중에 이식 가능한 구문 을 배우면 사람들이 잘못된 #!/bin/sh
shebang 을 사용하는 것이 좋다고 생각하게하고 다른 사람들이 그것을 사용하려고 할 때 스크립트를 깨뜨리는 경향이 있습니다. 이런 종류의 화염 미끼를 게시하지 않는 것이 좋습니다. :)
다른 사람들이 말했듯이, 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
경우 루프 전에 원하는 구분 기호로 설정할 수 있습니다 .
프로그래밍 방식으로 배열을 작성해야하는 경우 구분 된 문자열을 작성하면됩니다.
split+glob
연산자) 인 globbing을 비활성화하고 싶을 것입니다 .
배열을 대시로 시뮬레이션하는 방법 (배열의 여러 차원에 적용 할 수 있음) : ( seq
명령을 사용하려면 IFS
''(SPACE = 기본값)으로 설정 해야합니다 . 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 ###
################
local
모두에서 지원 bash
하고 dash
는 POSIX되지 않습니다. seq
POSIX 명령도 아닙니다. 코드가 $ IFS의 현재 값에 대해 약간의 가정을한다고 언급해야 할 것입니다 ( seq
변수를 사용하지 않고 인용 하면 피할 수 있습니다)