Cela fonctionne parfaitement sur OSX
#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
echo "${chars[i]}"
done
Mais lorsque je l'exécute sur Ubuntu, j'obtiens l'erreur suivante.
ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected
Je n'arrive pas à résoudre le problème. Aucune suggestion?
Réponses:
Vraisemblablement, vous exécutez le script en tant que:
Dans Ubuntu,
sh
est lié àdash
; commedash
il n'y a pas de concept de tableaux, vous obtenez l'erreur de syntaxe pour(
.Le script fonctionne parfaitement
bash
, donc ce serait bien si vous l'exécutiez commebash
argument:Maintenant, vous avez le
bash
shebang sur le script, vous pouvez donc rendre le script exécutable (chmod u+x ForLoopAlphabetTest.sh
) et l'exécuter en tant que:ou depuis le répertoire du script:
Notez également que votre script contient l'expansion d'accolade
{a..z}
et lafor
construction de style C :for (( ... ))
qui ne sont pas non plus prises en charge pardash
; donc si votre objectif est la portabilité, vous ne devriez regarder que lessh
syntaxes POSIX .la source
/bin/sh
n'importe quel système d'exploitation de type Unix, vous ne pourrez pas utiliser de tableaux. Bash (et certains autres shells) les ont ajoutés car ils sont très pratiques et ne peuvent pas toujours être facilement remplacés par un code plus portable. Cependant, pour votre script en particulier, vous pouvez le faire sans problème et sans utiliser de fonctionnalités spécifiques à bash. Êtes-vous intéressé par la façon de procéder?sh
Votre script utilise trois fonctionnalités du shell Bash qui ne sont pas fournies par tous les shells de style Bourne. Comme le dit heemayl , vous pouvez simplement exécuter ce script avec
bash
au lieu desh
. Votre ligne de hachage en haut (#!/bin/bash
) spécifiebash
mais n'est efficace que si vous exécutez le script, comme l' explique heemayl . Si vous passez le nom du script àsh
,sh
n'appellera pas automatiquementbash
, mais exécutera simplement le script. En effet, une fois votre script en cours d'exécution, la ligne de hachage n'a aucun effet .Votre autre alternative, si vous avez besoin d'écrire des scripts entièrement portables qui ne dépendent pas des fonctionnalités de Bash, est de changer votre script pour qu'il fonctionne sans eux. Les fonctionnalités Bash que vous utilisez sont:
( {a..z} )
, à laquelle vous attribuezchars
, crée un tableau et${chars[i]}
, qui apparaît dans votre boucle, y indexe.{a..z}
est étendu àa b c d e f g h i j k l m n o p q r s t u v w x y z
. Cependant, ce n'est pas une fonctionnalité universelle (ou standardisée) des shells de style Bourne, et Dash ne la prend pas en charge.for
syntaxe -loop . Bien que basée sur une expansion arithmétique , qui n'est pas elle-même spécifique à Bash (bien que certains shells très anciens et non conformes à POSIX ne l'aient pas non plus), lafor
boucle de style C est un Bash-ism et n'est pas largement portable pour d'autres coquilles.Bash est largement disponible, en particulier sur les systèmes GNU / Linux comme Ubuntu, et (comme vous l'avez vu) est également disponible sur macOS et de nombreux autres systèmes. Considérant combien vous utilisez des fonctionnalités spécifiques à Bash, vous pouvez simplement les utiliser, et assurez-vous simplement que vous utilisez Bash (ou un autre shell qui prend en charge les fonctionnalités que vous utilisez) lorsque vous exécutez vos scripts.
Cependant, vous pouvez les remplacer par des constructions portables si vous le souhaitez. Le tableau et la
for
boucle de style C sont faciles à remplacer; générer la gamme de lettres sans expansion d'accolade (et sans les coder en dur dans votre script) est la partie qui est un peu délicate.Tout d'abord, voici un script qui imprime toutes les lettres latines minuscules:
seq
commande génère des séquences numériques.$(
)
effectue la substitution de commande ,$(seq 97 122)
est donc remplacé par la sortie deseq 97 122
. Ce sont les codes de caractères poura
throughz
.printf
commande peut transformer les codes de caractères en lettres (par exemple, desprintf '\141'
impressionsa
, suivies d'une nouvelle ligne ), mais les codes doivent être en octal , tandis que lesseq
sorties ne sont qu'en décimal . J'ai donc utiliséprintf
deux fois: l'intérieurprintf %o $i
convertit les nombres décimaux (fournis parseq
) en octal, et est substitué dans laprintf
commande externe . (Bien qu'il soit également possible d'utiliser l' hexadécimal , ce n'est pas plus simple et semble moins portable .)printf
interprète\
suivi d'un nombre octal comme caractère avec ce code et\n
comme nouvelle ligne. Mais le shell utilise également\
un caractère d'échappement. Un\
devant$
empêchera$
de provoquer une expansion (dans ce cas, la substitution de commande ), mais je ne veux pas empêcher cela, donc je l'ai échappé avec un autre\
; c'est la raison\\
. Le deuxième\
avantn
n'a pas besoin d'être échappé car, contrairement à\$
,\n
n'a pas de signification particulière pour le shell dans une chaîne entre guillemets.'
) sont également une partie importante de la syntaxe des citations du shell, je ne les ai simplement pas utilisés dans ce script.Il est portable sur la plupart des systèmes de type Unix et ne dépend pas du shell de style Bourne que vous utilisez. Cependant, quelques systèmes de type Unix ne sont pas
seq
installés par défaut (ils ont tendance à utiliser à lajot
place, qui n'est pas installé par défaut la plupart des systèmes GNU / Linux). Vous pouvez utiliser une boucle avecexpr
ou une substitution arithmétique pour augmenter encore la portabilité, si vous devez:Cela utilise une
while
boucle avec la[
commande pour continuer à boucler uniquement lorsqu'il$i
est à portée.Plutôt que d'imprimer l'alphabet entier, votre script définit une variable
n
et imprime les premières$n
lettres minuscules. Voici une version de votre script qui ne repose sur aucune fonctionnalité spécifique à Bash et fonctionne sur Dash, mais nécessiteseq
:Ajuster la valeur des
n
changements combien de lettres sont imprimées, comme dans votre script.Voici une version qui ne nécessite pas
seq
:Là, il
$stop
y en a un de plus que le code de caractère de la dernière lettre qui doit être imprimé, donc j'utilise-lt
(moins que) plutôt que-le
(inférieur ou égal) avec la[
commande. (Il aurait également fonctionné pour fabriquerstop=$((i + n - 1))
et utiliser[ $i -le $stop ]
).la source