If / Else no shell script gera erros no Ubuntu para Windows

2

Veja um exemplo de script de shell simples:

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

Quando eu executo isso

sh ./test.sh

Eu recebo:

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

Não parece reconhecer o 'então' que tenho lá. Alguma pista sobre o porquê? Este é o Ubuntu para Windows, caso essa parte seja importante.

A execução de scripts de shell em geral não é um problema, apenas parece ter problemas com if / else.

    
por Matt Coady 16.11.2017 / 09:48

2 respostas

7

Existem dois problemas aqui. Primeiro, enquanto você tem uma linha de chamada shebang line , você está executando o script como sh script.sh . A linha shebang já especifica um interpretador para este script. Então, basta tornar o script executável:

chmod a+x ./test.sh

E, em seguida, execute-o:

./test.sh

Como alternativa, execute-o com o bash explicitamente:

bash ./test.sh

Isso fará com que seja executado com bash em vez de sh , que é um shell mais limitado e não entende == . O que nos leva ao segundo problema e por que isso falha. Estranhamente, você quer eq ou = , não == . O operador que testa a igualdade numérica em scripts shell POSIX ( sh é um shell compatível com POSIX) é -eq , enquanto o que testa a igualdade string é = e == não é uma coisa.

Portanto, se você quiser que seu script seja executado por sh , altere-o para:

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

Que verifica se a string 1 é igual à string 1 , ou para comparar numericamente, use:

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

Além disso, você tem outro problema. Só posso reproduzir o erro específico que você recebe em dash se eu adicionar um \r após o then . Esse é um problema clássico ao se mover entre o Windows e o Linux. Enquanto o Linux usa \n como caractere de fim de linha, o Windows termina suas linhas com \r\n . Esse caractere \r não é visível para o usuário, mas está lá e confunde o script. Então, você pode removê-lo com:

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

E, no futuro, use um editor de texto adequado para escrever seus scripts. Qualquer um que funcione no sistema WSL, ou um que possa pelo menos ser configurado para não adicionar \r às extremidades de suas linhas.

    
por terdon 16.11.2017 / 10:50
2

Vamos simplificar:

  • sh não é bash no Ubuntu (consulte este para referência).

  • [ é um comando, igual ao comando test . Não suporta == para comparação aritmética. Use -eq em vez disso. Este é um dos utilitários especificados pelos padrões POSIX , portanto funciona em bash e dash .

    if [ 1 -eq 1 ];
    then
        echo "it works!"
    fi
    
  • bash tem (( , que é chamado de expansão aritmética. Isso suporta == . Este recurso aparentemente foi emprestado de 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
    
  • Apesar do fato de dash não suportar if (()) , em qualquer shell $(( funcionará porque é obrigatório por padrão POSIX . Tomando apenas recursos que são comuns aos dois shells, poderíamos fazer algo parecido com isso enquanto ainda usamos == para comparações:

    
    $ 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
    
  • Poderíamos descartar a instrução if completamente e usar case (observe que o status de retorno está de acordo com C, não com o comportamento da shell, ou seja, true é 1 e false é 0, e não o contrário no 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 podemos ser sorrateiros com (ab) usando expansão aritmética:

    $ var=25 dash -c '_0(){ false;}; _1(){ true;}; if "_$((var==25))" ; then echo Y; else echo N; fi'
    
por Sergiy Kolodyazhnyy 16.11.2017 / 20:43