web-dev-qa-db-fra.com

Si / Else dans le script Shell génère des erreurs dans Ubuntu pour Windows

Voici un exemple de script simple:

#!/usr/bin/env bash
if [ 1 == 1 ]; then
echo "Something"
fi

Quand je lance ça

sh ./test.sh

Je reçois:

./test.sh: 4: ./test.sh: Syntax error: "fi" unexpected (expecting "then")

Il ne semble pas reconnaître le "alors" que j'ai ici. Un indice quant à pourquoi? C'est Ubuntu pour Windows au cas où cette partie importerait.

L'exécution de scripts Shell en général n'est pas un problème, il semble simplement avoir du mal avec if/else.

2
Matt Coady

Ici, nous avons deux problèmes. Tout d'abord, pendant que vous avez ligne Shebang appelant bash, vous exécutez le script en tant que sh script.sh. La ligne Shebang spécifie déjà un interpréteur pour ce script. Donc, il suffit de rendre le script exécutable:

chmod a+x ./test.sh

Et puis lancez-le:

./test.sh

Sinon, lancez-le explicitement avec bash:

bash ./test.sh

Cela le fera fonctionner avec bash au lieu de sh qui est un shell plus limité et qui ne comprend pas ==. Ce qui nous amène au deuxième problème et pourquoi cela échoue. Curieusement, vous voulez eq ou =, pas ==. L'opérateur qui teste l'égalité numérique dans les scripts de shell POSIX (sh est un shell compatible POSIX) est -eq, tandis que celui qui teste string l'égalité est = et == n'est pas une chose.

Donc, si vous voulez que votre script soit exécuté par sh, remplacez-le par:

if [ 1 = 1 ]; then
    echo "Something"
fi

Qui vérifie que la chaîne 1 est identique à la chaîne 1, ou pour comparer numériquement, utilisez:

if [ 1 -eq 1 ]; then
    echo "Something"
fi

De plus, vous avez un autre problème. Je ne peux reproduire l'erreur spécifique que vous obtenez dans dash que si j'ajoute un \r après le then. C’est un problème classique lorsqu’on passe de Windows à Linux. Tandis que Linux utilise \n comme caractère de fin de ligne, Windows termine ses lignes par \r\n. Ce caractère \r n'est pas visible par l'utilisateur, mais il existe et confond le script. Donc, vous pouvez l'enlever avec:

sed -i 's/\r//' ./test.sh

Et à l'avenir, utilisez un éditeur de texte approprié pour écrire vos scripts. Soit celui qui fonctionne dans le système WSL, ou celui qui peut au moins être configuré pour ne pas ajouter \r aux extrémités de ses lignes.

6
terdon

Restons simples:

  • sh n'est pas bash sur Ubuntu (voir this pour référence).

  • [ est une commande, identique à la commande test. Il ne supporte pas == pour la comparaison arithmétique. Utilisez -eq à la place. Il s’agit de l’un des utilitaires spécifiés par normes POSIX , qui fonctionne donc à la fois dans bash et dash.

    if [ 1 -eq 1 ];
    then
        echo "it works!"
    fi
    
  • bash a (( qui s'appelle expansion arithmétique. Ceci supporte ==. Cette fonctionnalité est apparemment empruntée à ksh Shell.

    $ var=25 bash -c 'if((var==5)); then echo Y;else echo "N";fi'      
    N
    $ var=25 bash -c 'if((var==25)); then echo Y;else echo "N";fi' 
    Y
    
  • Malgré le fait que dash ne prend pas en charge if (()), dans l'un ou l'autre Shell $(( fonctionnera car il est mandaté par norme POSIX . En prenant uniquement les caractéristiques communes aux deux shells, nous pourrions faire quelque chose comme ceci tout en utilisant toujours == pour les comparaisons:

    
    $ var=25 dash -c 'if [ $((var==25)) -eq 1 ];then echo Y; else echo N;fi'
    Y
    $ var=25 dash -c 'if [ $((var==5)) -eq 1 ];then echo Y; else echo N;fi' 
    N
    
  • Nous pourrions jeter complètement l'instruction if et utiliser case à la place (notez que le statut de retour est conforme à C, pas au comportement de Shell, c'est-à-dire que true vaut 1 et false vaut 0, et non l'inverse comme dans Shell) :

    $ dash -c 'case $((1==1)) in 1) echo "equal";; 0) echo "not equal";;esac'                                                                                                
    equal
    $ dash -c 'case $((1==2)) in 1) echo "equal";; 0) echo "not equal";;esac'                                                                                                
    not equal
    
  • ou nous pouvons devenir sournois avec (ab) en utilisant une expansion arithmétique:

    $ var=25 dash -c '_0(){ false;}; _1(){ true;}; if "_$((var==25))" ; then echo Y; else echo N; fi'
    
2