
Bourne シェル () で配列を使用しようとしています/bin/sh
。配列要素を初期化する方法は次の通りであることがわかりました。
arr=(1 2 3)
しかし、エラーが発生しています:
syntax error at line 8: `arr=' unexpected
この構文を見つけた投稿には、 用であると書かれていますが、Bourne シェル用の別の構文は見つかりませんでした。 構文はでもbash
同じですか?/bin/sh
答え1
/bin/sh
最近のシステムで Bourne シェルが採用されることはほとんどありません (Bourne シェルを採用した最後の主要システムの 1 つであった Solaris でさえ、Solaris 11 では /bin/sh が POSIX sh に切り替わりました)。/bin/sh
70 年代初頭には Thompson シェルが採用されていました。1979 年に Unix V7 で Bourne シェルがこれに取って代わりました。
/bin/sh
その後何年もの間、Bourne シェル (または BSD 上の無料の再実装である Almquist シェル) として使用されてきました。
現在では、 POSIX 言語/bin/sh
用のインタープリターまたは別のインタープリターがより一般的になっていますが、POSIXsh
言語自体は ksh88 言語のサブセット (およびいくつかの非互換性を持つ Bourne シェル言語のスーパーセット) に基づいています。
$1
Bourne シェルまたは POSIX sh 言語仕様は配列をサポートしていません。 むしろ、位置パラメータ ( 、、、$2
つまり$@
関数ごとに 1 つの配列) という1 つの配列しかありません。
ksh88 には で設定する配列がありましたset -A
が、構文が扱いにくく、あまり使いやすくなかったため、POSIX sh では指定されませんでした。
配列/リスト変数を持つ他のシェルには、csh
/ tcsh
、rc
、(主に ksh93 の方法で ksh 構文をコピーしたもの)、、(それぞれ異なる構文を持つ)(es
かつてUnix の後継となる予定だったシェルであり、最も一貫性のあるシェル)などがあります...bash
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 (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
dash で配列をシミュレートする方法 (配列の任意の次元数に適応できます): ( コマンドを使用するには、 が' ' (SPACE = デフォルト値) に設定されている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 ###
################