Como depurar um script bash? [fechadas]

159

Existe alguma maneira de depurar um script bash? Por exemplo, algo que imprime um tipo de log de execução como "linha de chamada 1", "linha de chamada 2" etc.

corvus
fonte
2
Há uma pergunta semelhante aqui: serverfault.com/questions/16204/…
Pausada até novo aviso.

Respostas:

195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

Eles fornecem um rastro do que está sendo executado. (Veja também 'Esclarecimento' na parte inferior da resposta.)

Às vezes, você precisa controlar a depuração no script. Nesse caso, como Cheeto me lembrou , você pode usar:

set -x

Isso ativa a depuração. Você pode desativá-lo novamente com:

set +x

(Você pode descobrir o estado de rastreamento atual analisando $-os sinalizadores atuais para x.)

Além disso, os shells geralmente fornecem opções ' -n' para 'sem execução' e ' -v' para o modo 'detalhado'; você pode usá-los em conjunto para verificar se o shell pensa que poderia executar seu script - ocasionalmente útil se você tiver uma cotação desequilibrada em algum lugar.


Há alegações de que a -xopção ' ' no Bash é diferente de outros shells (veja os comentários). O Manual do Bash diz:

  • -x

    Imprima um rastro de comandos simples, forcomandos, casecomandos, selectcomandos e forcomandos aritméticos e seus argumentos ou listas de palavras associadas depois de expandidos e antes de serem executados. O valor da PS4variável é expandido e o valor resultante é impresso antes do comando e de seus argumentos expandidos.

Isso parece não indicar um comportamento diferente. Não vejo outras referências relevantes para ' -x' no manual. Não descreve diferenças na sequência de inicialização.

Esclarecimento : Em sistemas como uma caixa típica do Linux, onde ' /bin/sh' é um link simbólico para ' /bin/bash' (ou onde quer que o executável Bash seja encontrado), as duas linhas de comando atingem o efeito equivalente de executar o script com o rastreamento de execução ativado. Em outros sistemas (por exemplo, Solaris, e algumas variantes mais modernas do Linux), /bin/shnão é o Bash, e as duas linhas de comando dariam resultados (ligeiramente) diferentes. Mais notavelmente ' /bin/sh', seria confundido por construções no Bash que ele não reconhece. (No Solaris, /bin/shé um shell Bourne; no Linux moderno, às vezes é Dash - um shell menor, mais estritamente apenas para POSIX.) Quando invocado por nome como esse, a linha 'shebang' ( #!/bin/bash'vs '#!/bin/sh'

O manual do Bash possui uma seção no modo Bash POSIX que, ao contrário de uma versão antiga e errônea desta resposta (veja também os comentários abaixo), descreve detalhadamente a diferença entre 'Bash chamado como sh' e 'Bash chamado como bash'

Ao depurar um script de shell (Bash), será sensato e sensato - até necessário - usar o shell nomeado na linha shebang com a -xopção Caso contrário, você poderá (obterá) comportamento diferente ao depurar e ao executar o script.

Jonathan Leffler
fonte
1
Ele especificou um bashscript. A execução de um script bash sh -xfará com que ele se comporte completamente diferente! Atualize sua resposta.
Lhunath
1
@lhunath: De que maneira 'sh -x' (ou 'bash -x') faz um script se comportar de maneira completamente diferente? Obviamente, ele gera informações de rastreamento para o stderr; isso é um dado (embora não mencionado na minha resposta). Mas o que mais? Uso 'bash' como 'sh' no Linux e MacOS X e não percebi um problema sério.
31416 Jonathan Leffler
6
Existem diferenças, na inicialização e no tempo de execução. Eles estão totalmente documentados na distribuição do Bash.
TheBonsai
4
Aqui está um link para o documento do bash: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Se o Bash for chamado com o nome sh, ele tentará imitar o comportamento de inicialização de versões históricas do sh como tanto quanto possível, enquanto em conformidade com o padrão POSIX bem'
thethinman
6
E use o prompt do PS4 para fornecer informações mais úteis, como:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani
28

Eu usei os seguintes métodos para depurar meu script.

set -efaz o script parar imediatamente se algum programa externo retornar um status de saída diferente de zero. Isso é útil se o seu script tentar lidar com todos os casos de erro e onde uma falha nesse procedimento deve ser interceptada.

set -x foi mencionado acima e é certamente o mais útil de todos os métodos de depuração.

set -n também pode ser útil se você deseja verificar se há erros de sintaxe no seu script.

stracetambém é útil para ver o que está acontecendo. Especialmente útil se você não tiver escrito o script.


fonte
1
Rastrear um script (ou seja, rastrear um shell executando o script) é um método estranho de depuração de shell (mas pode funcionar para um conjunto limitado de problemas).
TheBonsai
1
Admito que é estranho e também muito detalhado, mas se você limitar a saída do strace a alguns syscalls, isso se tornará útil.
1
Observe que isso strace -fé necessário se você também deseja encontrar erros nos processos iniciados pelo script. (o que o torna muitas vezes mais detalhado, mas ainda útil se você o limitar aos syscalls nos quais está interessado).
usar o seguinte código
set -eé ... controverso .
Charles Duffy
12

Esta resposta é válida e útil: https://stackoverflow.com/a/951352

Mas acho que os métodos de depuração de script "padrão" são ineficientes, não intuitivos e difíceis de usar. Para aqueles acostumados a depuradores sofisticados de GUI que colocam tudo ao seu alcance e facilitam o trabalho para problemas fáceis (e possíveis para problemas difíceis), essas soluções não são muito satisfatórias.

O que faço é usar uma combinação de DDD e bashdb. O primeiro executa o último e o último executa seu script. Isso fornece uma interface do usuário com várias janelas com a capacidade de percorrer o código no contexto e exibir variáveis, pilha, etc., sem o esforço mental constante para manter o contexto em sua cabeça ou continuar listando novamente a fonte.

Há orientações sobre como configurar isso aqui: http://ubuntuforums.org/showthread.php?t=660223

Stabledog
fonte
Acabei de descobrir ddd graças à sua resposta. No Ubuntu 12.04.3 (64bit), a versão apt-sources não funciona. Eu tive que compilar e instalar a partir da fonte para começar a depurar meu script bash. As instruções aqui - askubuntu.com/questions/156906/… ajudaram.
chronodekar
Sim, isso é um problema. Eu resolvi lhe algum tempo de volta com algum scripting - instalações 'dddbash' / constrói DDD, remove a versão antiga, se é errado, instala bashdb, etc. (Resposta foi editado com esta informação agora)
Stabledog
10

Você também pode escrever "set -x" dentro do script.

Cheeto
fonte
4
E você pode escrever 'set + x' para desativá-lo.
Jonathan Leffler
10

Encontrei o utilitário shellcheck e algumas pessoas acham interessante https://github.com/koalaman/shellcheck

Um pequeno exemplo:

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

corrigir o erro, primeira tentativa ...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

Vamos tentar de novo...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

encontre agora!

É apenas um pequeno exemplo.

Solucionador de equações
fonte
1
E está online !
Nick Westgate
Felizmente, a ferramenta evoluiu até o ponto em que também encontra o bug restante.
tripleee
3

Instale o VSCode , adicione a extensão de depuração do bash e você estará pronto para depurar no modo visual. veja Aqui em ação.

insira a descrição da imagem aqui

yantaq
fonte
3

Use eclipse com os plugins com shell e basheclipse.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

Para shell: Faça o download do zip e importe-o para o eclipse via ajuda -> instalar novo software: arquivo local Para o basheclipse: Copie os frascos no diretório dropins do eclipse

Siga as etapas fornecidas https://sourceforge.net/projects/basheclipse/files/?source=navbar

insira a descrição da imagem aqui

Eu escrevi um tutorial com muitas capturas de tela em http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html

Dietrich Schroff
fonte
2
Esta é uma resposta apenas para o limite do link (veja também aqui ). Você deve expandir sua resposta para incluir o máximo de informações possível aqui, pelo menos o mínimo necessário para realmente realizar o que está sugerindo e usar os links apenas para referência. Basicamente, as postagens no Stack Overflow (e todo o Stack Exchange) devem ser independentes. Isso significa que informações suficientes precisam estar em sua resposta, de modo que o leitor não precise sair do local para obter instruções. No momento, esse não é o caso desta resposta.
Makyen 8/08/19
esta é a primeira resposta que encontrei depois de analisar muitas que realmente mostram que a depuração verdadeira é possível. As respostas padrão "set + x" correspondem perfeitamente a uma resposta independente, mas quase intencionalmente ignoram as verdadeiras perguntas sobre a depuração verdadeira. Aplaudo esta resposta 👏
simbo1905
2

Eu construí um depurador Bash. Apenas tente. Espero que ajude https://sourceforge.net/projects/bashdebugingbash

abadjm
fonte
Atualmente, o BDB é suportado nos idiomas inglês e espanhol. Para alterar o idioma, editar o arquivo / etc / default / bdb
abadjm
a captura de tela parece interessante, mas não consegui executá-la "bdb.sh: linha 32: bdbSTR [1]: variável não acoplada"; btw mostrará os valores atuais de todas as variáveis ​​definidas a cada passo que fazemos no código?
Potência de Aquário
2

ajuste + x = @ECHO OFF, ajuste -x = @ECHO ON.


Você pode adicionar uma -xvopção ao Shebang padrão da seguinte maneira:

#!/bin/bash -xv  

-x: Exibe comandos e seus argumentos à medida que são executados.
-v: Exibe as linhas de entrada do shell conforme são lidas.


ltraceé outro utilitário Linux semelhante ao strace. No entanto, ltracelista todas as chamadas de biblioteca que estão sendo chamadas em um processo executável ou em execução. Seu próprio nome vem do rastreamento de chamadas de biblioteca. Por exemplo:

ltrace ./executable <parameters>  
ltrace -p <PID>  

Fonte

Premraj
fonte
1

Algum truque para depurar scripts:

Usando set -[nvx]

Além de

set -x

e

set +x

para parar o despejo.

Eu gostaria de falar sobre set -vqual despejo é menor e menos desenvolvido.

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Despejar variáveis ​​ou rastreamento em tempo real

Para testar algumas variáveis, eu uso em algum momento isso:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

para adicionar:

declare >&2 -p var1 var2

na linha 18 e executando o script resultante (com args ), sem precisar editá-los.

claro, isso poderia ser usado para adicionar set [+-][nvx]:

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

adicionará declare -p v1 v2 >&2após a linha 18, set -xantes da linha 22 e set +xantes da linha 26.

pequena amostra:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

Nota: Os cuidados $LINENOserão afetados por modificações on-the-fly !

(Para ver o script resultante sem execução, basta soltar bash <(e ) arg1 arg2)

Passo a passo, tempo de execução

Dê uma olhada na minha resposta sobre como criar perfis de bash scripts

F. Hauri
fonte
0

Há uma boa quantidade de detalhes no registro de scripts de shell por meio de variáveis ​​globais do shell. Podemos emular o tipo semelhante de log no shell script: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

A postagem tem detalhes sobre a introdução de níveis de log como INFO, DEBUG, ERROR. Detalhes de rastreamento, como entrada de script, saída de script, entrada de função, saída de função.

Exemplo de log:

insira a descrição da imagem aqui

Piyush Chordia
fonte