Como depurar um script bash?

135

Estou tendo alguns problemas com alguns scripts no bash, sobre erros e comportamentos inesperados. Gostaria de investigar as causas dos problemas para poder aplicar correções. Existe uma maneira de ativar algum tipo de "modo de depuração" para o bash, para obter mais informações?

Braiam
fonte

Respostas:

132

Inicie seu script bash com bash -x ./script.shou adicione seu script set -xpara ver a saída de depuração.


Adicional com bash4.1 ou posterior:

Se você deseja gravar a saída de depuração em um arquivo separado, adicione isso ao seu script:

exec 5> debug_output.txt
BASH_XTRACEFD="5"

Consulte: https://stackoverflow.com/a/25593226/3776858


Se você quiser ver os números das linhas, adicione isto:

PS4='$LINENO: '


Se você tiver acesso ao loggercomando, poderá usá-lo para gravar a saída de depuração via syslog com carimbo de data / hora, nome do script e número da linha:

#!/bin/bash

exec 5> >(logger -t $0)
BASH_XTRACEFD="5"
PS4='$LINENO: '
set -x

# Place your code here

Você pode usar a opção -pde loggercomando para definir um recurso e um nível individuais para gravar a saída via syslog local em seu próprio arquivo de log.

Cyrus
fonte
7
-v também pode ajudar (imprime cada linha à medida que são executadas. pode ser combinada com -x). E veja também: bashdb.sourceforge.net
Olivier Dulac
4
outro recurso maravilhoso é: shellcheck.net
Olivier Dulac
O que "exec 5>" faz?
aggsol
3
@aggsol: Se você usar o BASH_XTRACEFD="5"bash, grava a saída de rastreamento gerada quando set -xativada no descritor de arquivo 5. exec 5> >(logger -t $0)redireciona a saída do descritor de arquivo 5 para o loggercomando.
Cyrus
1
Basta saber, você pode obter o número da linha e o caminho ou o nome do shell script no PS4?
Iloveretards
55

Usando set -x

Eu sempre uso set -xe set +x. Você pode agrupar áreas nas quais deseja ver o que está acontecendo com elas para ativar / desativar a verbosidade.

#!/bin/bash

set -x
..code to debug...
set +x

log4bash

Além disso, se você fez um trabalho de desenvolvimento e está familiarizado com o estilo dos registradores que usam os nomes log4j, log4perl etc., convém usar o log4bash .

excerto

Vamos ser sinceros - o eco simples e antigo simplesmente não é suficiente. log4bash é uma tentativa de ter um melhor registro para scripts do Bash (ou seja, tornar o log no Bash menos trabalhoso).

A partir daí, você pode fazer coisas assim nos seus scripts do Bash:

#!/usr/bin/env bash
source log4bash.sh

log "This is regular log message... log and log_info do the same thing";

log_warning "Luke ... you turned off your targeting computer";
log_info "I have you now!";
log_success "You're all clear kid, now let's blow this thing and go home.";
log_error "One thing's for sure, we're all gonna be a lot thinner.";

# If you have figlet installed -- you'll see some big letters on the screen!
log_captains "What was in the captain's toilet?";

# If you have the "say" command (e.g. on a Mac)
log_speak "Resistance is futile";

Resultando neste tipo de saída:

    ss1

log4sh

Se você precisar de algo mais portátil, também há os mais antigos log4sh. Trabalhos similares a log4bash, disponíveis aqui:

slm
fonte
No Ubuntu, eu tenho alias say="spd-say"no meu .bashrc, que imita o saycomando de outras distros ou OS X.
Doorknob
1
set -vx seria uma boa combinação se usado com trap - trap read debug. Isso permite que você passar por cima de linha por linha e ver os resultados
Magnus Melwin
34

Há um depurador bash, o bashdb , que é um pacote instalável em muitas distribuições. Ele usa o modo de depuração estendido interno do bash ( shopt -s extdebug). Parece muito com gdb; aqui está uma sessão de amostra para dar um sabor:

$ ls
1st.JPG  2ndJPG.JPG
$ cat ../foo.sh
for f in *.JPG
do
  newf=${f/JPG/jpg}
  mv $f $newf
done
$ bashdb ../foo.sh
(foo.sh:1):
1:      for f in *.JPG
bashdb<0> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<1> next
(foo.sh:4):
4:        mv $f $newf

Como no gdb, a instrução é mostrada imediatamente antes de ser executada. Portanto, podemos examinar variáveis ​​para ver o que a declaração fará antes de fazê-lo.

bashdb<2> print $f $newf
1st.JPG 1st.jpg
bashdb<3> next
(foo.sh:1):
1:      for f in *.JPG
bashdb<4> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<5> next
(foo.sh:4):
4:        mv $f $newf
bashdb<6> print $f $newf
2ndJPG.JPG 2ndjpg.JPG

Não é isso que queremos! Vejamos a expansão de parâmetros novamente.

bashdb<7> print $f ${f/JPG/jpg}
2ndJPG.JPG 2ndjpg.JPG
bashdb<8> print $f ${f/JPG$/jpg}
2ndJPG.JPG 2ndJPG.JPG
bashdb<9> print $f ${f/%JPG/jpg}
2ndJPG.JPG 2ndJPG.jpg

OK, isso funciona. Vamos definir newfo valor correto.

bashdb<10> eval newf=${f/%JPG/jpg}
$? is 0
bashdb<11> print $f $newf
2ndJPG.JPG 2ndJPG.jpg

Parece bom. Continue o script.

bashdb<12> next
Debugged program terminated normally. Use q to quit or R to restart.
$ ls
1st.jpg  2ndJPG.jpg
Mark Plotnick
fonte
20

O método padrão para depurar scripts na maioria dos shells baseados em Bourne, como o bash, é escrever set -xna parte superior do seu script. Isso tornará o bash mais detalhado sobre o que está sendo feito / executado e como os argumentos são avaliados.

-x  Print commands and their arguments as they are executed.

isso é útil para o intérprete ou para scripts internos. Por exemplo:

$ find "$fileloc" -type f -prune "$filename" -print
+ find /var/adm/logs/morelogs -type f -prune '-name *.user' -print
find: unknown predicate '-name *.user'
$ find "$fileloc" -type f -prune $filename -print
+ find /var/adm/logs/morelogs -type f -prune -name '*.user' -print
find: '/var/adm/logs/morelogs': No such file or directory

No exemplo acima, podemos ver por que a localização está falhando devido a aspas simples.

Para desativar o recurso, basta digitar set +x.

Braiam
fonte
13

Usando o Eclipse

Você pode usar o ambiente combinado do Eclipse e Shelled com o script "_DEBUG.sh" vinculado abaixo.

Cascas de comutação

Por padrão, a ferramenta de desenvolvimento Shelled usa /bin/dashcomo intérprete. Alterei isso para /bin/bashter uma melhor compatibilidade com a maioria dos exemplos de shell na Web e no meu ambiente.

NOTA: Você pode alterar isso acessando: Janela -> Preferências -> Shell Script -> Intérpretes

Instruções de instalação

O pacote Debugger possui as etapas para usar o _DEBUG.shscript para sua depuração de script, que é basicamente (o readme.txt):

  1. Criar projeto de shell script: Arquivo -> Novo -> Outro -> Shell Script -> Assistente de projeto de script de shell .
  2. Crie um arquivo de script Bash: Arquivo -> Novo -> Arquivo . Para este exemplo, será script.sh. A extensão deve ser ".sh" e é uma obrigação.
  3. Copie o arquivo _DEBUG.shpara a pasta do projeto.
  4. Insira o seguinte texto na parte superior do arquivo script.sh:

    . _DEBUG.sh
  5. Se o arquivo for criado no Microsoft Windows, execute o Arquivo -> Converter delimitadores de linha em -> Unix .

  6. Defina uma configuração de inicialização de depuração: Execute -> Configurações de Depuração -> Script Bash ... Existem 2 campos para definir aqui:

    a) "Script Bash:" - Caminho na área de trabalho do Eclipse para o script Bash para depuração.
    e) "Porta do depurador:" 33333

  7. Alterne para a perspectiva Debug. Inicie a sessão de depuração. Iniciar a script.shpartir do shell bash.

A interface do usuário de depuração do bash

insira a descrição da imagem aqui

Este depurador do bash possui todos os recursos dos depuradores de programação padrão, como:

  • Alternar ponto de interrupção
  • Operação passo a passo única
  • Funções e sub-rotinas Step-in, Step-out, Step-over
  • Examinando código ou variáveis ​​a qualquer momento enquanto o script está em execução

O IDE Shelled (Shell Script Editor) (Ambiente de desenvolvimento integrado) possui um bônus adicional de executar verificação de contexto, realçar e recuar enquanto escreve seu script. Se não recuar corretamente, você poderá imediatamente sinalizar / muitos erros locais lá.

Existem outros benefícios do IDE , como:

  • Lista de tarefas TODO
  • Tarefa Mylyn
  • Lista de favoritos
  • Edição de várias janelas
  • Compartilhamento remoto do ambiente
LD James
fonte
Dica legal. É bom saber que o Bash pode ser depurado assim.
slm
8

Um recurso maravilhoso apareceu nos últimos anos: http://shellcheck.net

mostra mais do que o bash normal, permitindo encontrar facilmente aquelas citações não fechadas ou suportes encaracolados, etc.

Apenas certifique-se de não colar informações confidenciais (ips, senhas etc.) na rede ... (especialmente por ser http, sem criptografia) (acredito que o shellcheck também esteja disponível para download, mas não tenho certeza)

Olivier Dulac
fonte
6

basta usar:

#!/bin/bash -x

o mesmo para shell:

#!/bin/sh -x
Gery
fonte
6

Atualmente, existe o VS Code Bash Debug.

https://marketplace.visualstudio.com/items?itemName=rogalmic.bash-debug

Possui 'Step in / out / over' e também mostra o valor de cada variável.

Captura de tela VS Code Bash Debug

Henrique Lemos Ribeiro
fonte
essa resposta não aborda a questão no contexto certo; assumindo linha de comando desde que o IDE não foi mencionado
qodeninja 12/09