você está aqui: Home  → Arquivo de Mensagens

Problemas IDIOTAMENTE comuns quando se cria um script em Shell

Colaboração: Rafael Henrique da Silva Correia

Data de Publicação: 18 de junho de 2012

Olhando o script abaixo (sem escrevê-lo no Shell :P) o que você diria que ele escreve na tela?? Lembrando que a variável $? informa o retorno do status do último comando se o comando executou com sucesso ele será 0, se o comando deu algum erro ele será diferente de 0. Olhe:

  #!/bin/bash
  echo "TESTANDO 123..."
  if [ "$?" -ne 0 ]; then
    echo "não igual a 0"
  elif [ "$?" -eq 0 ]; then
    echo "igual a 0"
  else
    echo "Nem um nem outro"
  fi

Se você achou (assim como eu achei) que ele escreveria na tela "não igual a 0" você está redondamente enganado! Descobri que cometi um erro deste tipo em um script que eu estava fazendo (com certeza muuuuito maior do que este).

Por que o script tem este comportamento?

A variável $? como citado acima informa o retorno do status do último comando se o comando executou com sucesso ele será 0, se o comando deu algum erro ele será diferente de 0 .... porém o if faz uso do comando test (representado por []), então o primeiro if retornará um status e esse novo status será armazenado dentro de $?, desta forma DESGRAÇANDO todo o script.

E para corrigir?

Para corrigir basta criar uma variável auxiliar desta forma:

  #!/bin/bash
  
  echo "TESTANDO 123..."
  VARAUX="$?"
  
  if [ "$VARAUX" -ne 0 ]; then
    echo "não igual a 0"
  elif [ "$VARAUX" -eq 0 ]; then
    echo "igual a 0"
  else
    echo "Nem um nem outro"
  fi

Eis que agora a saída do script será:

  rafael@zion:~$ ./teste1.sh
  TESTANDO 123...
  igual a 0

Como depurar programas em shell?

Geralmente no caso deste problema eu faria o seguinte, escreveria echos para ver o conteúdo da variável $? durante a execução do script da seguinte maneira:

  #!/bin/bash
  echo "TESTANDO 123..."
  echo "$?"
  if [ "$VARAUX" -ne 0 ]; then
    echo "$?"
    echo "não igual a 0"
  elif [ "$VARAUX" -eq 0 ]; then
    echo "$?"
    echo "igual a 0"
  else
    echo "$?"
    echo "Nem um nem outro"
  fi

E para finalizar existe um parâmetro muito bom do bash próprio para fins de depuração:

  rafael@zion:~$ bash -x teste1.sh
  + echo 'TESTANDO 123...'
  TESTANDO 123...
  + echo 0
  0
  + '[' '' -ne 0 ']'
  teste1.sh: line 6: [: : esperado expressão de número inteiro
  + '[' '' -eq 0 ']'
  teste1.sh: line 11: [: : esperado expressão de número inteiro
  + echo 2
  2
  + echo 'Nem um nem outro'
  Nem um nem outro

Desta forma você conseguirá ver que rumo seu script está tomando!

Esta dica não é nada complexa, porém agradeço se alguém postar outras formas de depuração de scripts em shell, eu somente iniciei o assunto e aqui no Dicas-l já li muitos comentários legais e construtivos a respeito das dicas que eu já postei!

Conhecimento traz conhecimento! Vamos colaborar!

Até+



Veja a relação completa dos artigos de Rafael Henrique da Silva Correia

 

 

Opinião dos Leitores

Rafael Henrique da Silva Correia
28 Jun 2012, 08:44
Obrigado a todos pelos comentários!
Rafael Henrique da Silva Correia
28 Jun 2012, 08:43
Sérgio Luiz Araújo Silva ... isso funciona

comando desejado && echo "ok" || echo "deu pau no comando"

Porém se eu tenho que testar 3 ou 4 comandos usando and e or isso fica muito complicado. Quando eu jogo o valor do status em uma variável consigo usar os ifs da forma que eu desejar.

Até+
Rafael Henrique da Silva Correia
28 Jun 2012, 08:40
Fernando Roxo muito boa dica! Usarei o -xv com certeza!
Rafael Henrique da Silva Correia
28 Jun 2012, 08:39
Simmm pessoal o else está lá desnecessariamente... porém isso é um script altamente didático e não tem função útil.
Rafael Henrique da Silva Correia
28 Jun 2012, 08:38
Zé, o título tem que parecer engraçado ao meu ver... se o título não chama atenção eu geralmente nem abro a dica para ler.
Rafael Henrique da Silva Correia
28 Jun 2012, 08:37
Caro Alysson Bruno o script final é este:

#!/bin/bash

echo "TESTANDO 123..."
VARAUX="$?"

if [ "$VARAUX" -ne 0 ]; then
echo "não igual a 0"
elif [ "$VARAUX" -eq 0 ]; then
echo "igual a 0"
else
echo "Nem um nem outro"
fi

Portanto O VARAUX vai pegar o status do comando echo, pois este é o objetivo do script.

27 Jun 2012, 07:35
Caro Rafael Henrique da Silva Correia,

Seu titulo não ficou bom.

Bruno Jesus
18 Jun 2012, 18:40
Se o valor não é zero ele vai mostrar o primeiro texto, se não ele tem que ser zero. Não precisa da segunda comparação. Atualmente o else lá é desnecessário, certo?
Fernando Roxo
18 Jun 2012, 16:21
Quanto ao "debug", todos os meus scripts têm no início um texto do tipo :

# Debug
# set -xv

Sim, o comando "set" acima está comentado. Para ativá-lo basta descomentar a linha. Mas porque "-xv" e não "-x" ? Porque o "-v" vai listar a linha de comando *antes* da expansão/substituição, mostrando a linha antes e depois podemos verificar se a substituição foi a que se queria.

No caso específico deste tipo de código me parece só haver 2 possibilidades para a comparação, ou é igual a zero ou diferente. A opção "nenhum dos dois" não parece ter muita utilidade. Portanto bastaria haver as cláusulas "if" e "else", o que torna necessária a variável VARAUX.

Atenção, eu não estou dizendo que a variável não tem utilidade ! Em várias situações existe mesmo a necessidade. Por razões históricas, do tempo que trilobita era tira-gosto, eu uso RC (return code, coisa de mainframe, imagine só. :)). No caso de querer tratar vários valores eu uso algo como :

<comando>
RC=$?

case "$RC" in
0) echo "Tudo bem..."
;;

[1-5]) echo "Erro entre 1 e 5"
;;

127) echo "Arquivo não encontrado"
;;

*) echo "Erro $RC desconhecido, abortando."
exit $RC
;;
esac

Provavelmente a interface WEB vai destruir a estruturação do texto, mas acho que vai dar para entender. :)

Felipe Santos - Rasputin
18 Jun 2012, 15:21
Uma outra dica pra depurar scripts em sheel é utilizar o comando set -x no inicio do comando. assim ele irá printar todos os passos executaos pelo script
Raul Libório
18 Jun 2012, 12:23
Concordo e faço como o Sérgio.
Por exemplo, em scripts que necessitem criar um diretório, faço da seguinte maneira:

[ -d /path/do/diretorio ] || mkdir /path/do/diretorio

Aqui ele verificará se o diretório existe. Caso não, ele o criará.
Alysson Bruno
18 Jun 2012, 07:25
echo também é um comando do Shell Script, então seu script está errado, você deve colocar o VARAUX antes do echo também.
Sérgio Luiz Araújo Silva
18 Jun 2012, 06:54
Não sou assim tão bom em shell mas acho que há outro caminho

comando desejado && echo "ok" || echo "deu pau no comando"

caso o comando dê certo o shell mostra ok, caso contrário
ele vai para o "ou" mostrando a mensagem de erro
*Nome:
Email:
Me notifique sobre novos comentários nessa página
Oculte meu email
*Texto:
 
  Para publicar seu comentário, digite o código contido na imagem acima
 


Powered by Scriptsmill Comments Script