
Ich versuche, Arrays in der Bourne-Shell ( /bin/sh
) zu verwenden. Ich habe herausgefunden, dass Array-Elemente folgendermaßen initialisiert werden:
arr=(1 2 3)
Es tritt jedoch ein Fehler auf:
syntax error at line 8: `arr=' unexpected
In dem Beitrag, in dem ich diese Syntax gefunden habe, steht, dass sie für gilt bash
, aber ich konnte keine separate Syntax für die Bourne-Shell finden. Gilt die Syntax /bin/sh
auch für ?
Antwort1
/bin/sh
gibt es heutzutage auf kaum noch Systemen eine Bourne-Shell (selbst Solaris, eines der letzten großen Systeme, das sie enthielt, ist in Solaris 11 für sein /bin/sh auf eine POSIX-Shell umgestiegen). /bin/sh
war in den frühen 70ern die Thompson-Shell. Die Bourne-Shell ersetzte sie 1979 in Unix V7.
/bin/sh
war danach viele Jahre lang die Bourne-Shell (oder die Almquist-Shell, eine freie Neuimplementierung auf BSDs).
Heutzutage /bin/sh
wird üblicherweise ein Interpreter oder ein anderer für die POSIX- sh
Sprache verwendet, die selbst auf einer Teilmenge der Sprache von ksh88 (und einer Obermenge der Bourne-Shell-Sprache mit einigen Inkompatibilitäten) basiert.
Die Bourne-Shell oder die POSIX-Sprachspezifikation sh unterstützen keine Arrays. Oder besser gesagt, sie haben nur ein Array: die Positionsparameter ( $1
, $2
, $@
, also auch ein Array pro Funktion).
ksh88 hatte Arrays, die Sie mit festlegen konnten set -A
, aber das wurde nicht im POSIX-sh angegeben, da die Syntax umständlich und nicht sehr brauchbar ist.
Andere Shells mit Array-/Listenvariablen sind: csh
/ tcsh
, rc
, es
, bash
(die die KSH-Syntax größtenteils auf die KSH93-Art kopiert haben), yash
, zsh
, fish
jede mit einer anderen Syntax ( rc
die Shell des einstigen Nachfolgers von Unix fish
und zsh
die konsistenteste)...
Im Standard sh
(funktioniert auch in modernen Versionen der Bourne-Shell):
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)
(Beachten Sie, dass in der Bourne-Shell und in ksh88 $IFS
das Leerzeichen enthalten sein muss, damit "$@"
es richtig funktioniert (ein Fehler), und dass Sie in der Bourne-Shell nicht auf die darüber liegenden Elemente zugreifen können $9
( ${10}
funktioniert nicht, Sie können trotzdem eine Funktion ausführen shift 1; echo "$9"
oder eine Schleife darüber ausführen)).
Antwort2
Wie die anderen bereits gesagt haben, hat die Bourne Shell keineWAHRArrays.
Je nachdem, was Sie tun müssen, sollten jedoch abgegrenzte Zeichenfolgen ausreichen:
sentence="I don't need arrays because I can use delimited strings"
for word in $sentence
do
printf '%s\n' "$word"
done
Wenn die üblichen Trennzeichen (Leerzeichen, Tabulator und Zeilenumbruch) nicht ausreichen, können SieIFS
zu einem beliebigen Trennzeichen vor der Schleife.
Und wenn Sie das Array programmgesteuert erstellen müssen, können Sie einfach eine durch Trennzeichen getrennte Zeichenfolge erstellen.
Antwort3
In der einfachen Bourne-Shell gibt es keine Arrays. Sie können ein Array folgendermaßen erstellen und durchlaufen:
#!/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
Egal, welche Art der Verwendung von Arrays sh
Sie wählen, es wird immer umständlich sein. Erwägen Sie die Verwendung einer anderen Sprache wie Python
oder , Perl
wenn Sie können, es sei denn, Sie sind an eine sehr eingeschränkte Plattform gebunden oder möchten etwas lernen.
Antwort4
Eine Möglichkeit, Arrays in Dash zu simulieren (kann für jede beliebige Anzahl von Dimensionen eines Arrays angepasst werden): (Bitte beachten Sie, dass für die Verwendung des seq
Befehls erforderlich ist, dass IFS
auf „ “ gesetzt ist (SPACE = Standardwert). Sie können stattdessen while ... do ...
oder do ... while ...
Schleifen verwenden, um dies zu vermeiden (ich habe mich seq
an eine bessere Veranschaulichung dessen gehalten, was der Code bewirkt).)
#!/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 ###
################