J'essaie d'utiliser des tableaux dans Bourne Shell (/bin/sh
). J'ai trouvé que la façon d'initialiser les éléments d'un tableau est la suivante:
arr=(1 2 3)
Mais il rencontre une erreur:
syntax error at line 8: `arr=' unexpected
Maintenant, le message où j'ai trouvé cette syntaxe dit que c'est pour bash
, mais je n'ai trouvé aucune syntaxe distincte pour Bourne Shell. La syntaxe est-elle la même pour /bin/sh
ainsi que?
/bin/sh
n'est presque jamais un Bourne Shell sur aucun système de nos jours (même Solaris qui était l'un des derniers systèmes majeurs à l'inclure est maintenant passé à un POSIX sh pour son/bin/sh dans Solaris 11). /bin/sh
était le Thompson Shell au début des années 70. Le Bourne Shell l'a remplacé dans Unix V7 en 1979.
/bin/sh
a été le Bourne Shell pendant de nombreuses années par la suite (ou le Almquist Shell, une réimplémentation gratuite sur les BSD).
Aujourd'hui, /bin/sh
est plus communément un interpréteur ou un autre pour le langage POSIX sh
qui est lui-même basé sur un sous-ensemble du langage de ksh88 (et un sur-ensemble du langage Bourne Shell avec quelques incompatibilités).
Le Bourne Shell ou la spécification du langage POSIX sh ne prennent pas en charge les tableaux. Ou plutôt ils n'ont qu'un seul tableau: les paramètres de position ($1
, $2
, $@
, donc un tableau par fonction également).
ksh88 avait des tableaux que vous définissez avec set -A
, mais cela n'a pas été spécifié dans le sh POSIX car la syntaxe est maladroite et peu utilisable.
D'autres shells avec des variables tableau/listes incluent: csh
/tcsh
, rc
, es
, bash
(qui copiait principalement la syntaxe ksh de la manière ksh93), yash
, zsh
, fish
chacun avec une syntaxe différente (rc
le Shell du futur successeur d'Unix, fish
et zsh
étant les plus cohérents) ...
En standard sh
(fonctionne également dans les versions modernes du 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)
(notez que dans le Bourne Shell et le ksh88, $IFS
doit contenir le caractère espace pour "$@"
pour fonctionner correctement (un bug), et dans le Bourne Shell, vous ne pouvez pas accéder aux éléments ci-dessus $9
(${10}
ne fonctionnera pas, vous pouvez toujours faire shift 1; echo "$9"
ou bouclez dessus)).
Il n'y a pas de tableaux dans le Bourne Shell ordinaire. Vous pouvez utiliser la méthode suivante pour créer un tableau et le parcourir:
#!/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
Quelle que soit la façon d'utiliser les tableaux dans sh
choisiriez-vous que ce sera toujours lourd. Pensez à utiliser une langue différente telle que Python
ou Perl
si vous le pouvez, sauf si vous êtes coincé avec une plate-forme très limitée ou si vous voulez apprendre quelque chose.
Comme les autres l'ont dit, le Bourne Shell n'a pas de vrais tableaux .
Cependant, selon ce que vous devez faire, des chaînes délimitées devraient suffire:
sentence="I don't need arrays because I can use delimited strings"
for Word in $sentence
do
printf '%s\n' "$Word"
done
Si les délimiteurs typiques (espace, tabulation et nouvelle ligne) ne suffisent pas, vous pouvez définir IFS
sur le délimiteur que vous souhaitez avant la boucle.
Et si vous devez créer le tableau par programme, vous pouvez simplement créer une chaîne délimitée.
Un moyen de simuler des tableaux dans un tiret (il peut être adapté à n'importe quel nombre de dimensions d'un tableau): (Veuillez noter que l'utilisation de la commande seq
nécessite que IFS
soit défini sur '' (ESPACE = la valeur par défaut.) Vous pouvez utiliser while ... do ...
ou do ... while ...
boucle à la place pour éviter cela (j'ai gardé seq
dans le cadre d'une meilleure illustration de ce que fait le code).)
#!/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 ###
################