Existe uma maneira simples de descobrir a última linha executada em um script bash?

2

Ao responder a esta pergunta, por favor, tenha em mente que eu sou iniciante e um pouco fora do meu alcance.

Estou executando um script bash que contém um loop for que será executado milhares de vezes. Em algum lugar deste loop for, o código geralmente fica preso (o número mais baixo de iterações que vi para parar é 32, mas a maioria parou em 4000s - ele deve rodar 5.000 vezes, às vezes completa a tarefa). Eu gostaria de depurar esse problema. Obviamente, eu não quero inserir manualmente centenas de milhares de linhas de código na janela de comando e esperar por aquela em que ela ficará presa.

Existe uma maneira simples de descobrir qual foi a última linha executada ou tentada a executar? (Tendo em conta que, quando correm mal, o terminal parece estar congelado - por vezes, todo o sistema deixa de funcionar e requer uma reposição imediata para o iniciar novamente.) Achei que esta poderia ser uma característica do eco. Eu encontrei esta pergunta e resposta , mas não tenho certeza do que "quando os comandos representam uma linha específica no meu script do ponto de vista do analisador "significa e, portanto, se for aplicável. Eu também estou muito confuso com o que este código realmente faz e gostaria de receber a explicação de manequins se este código me ajudar.

Esta é a resposta que estou procurando? Existe outra solução para este problema?

    
por Reluctant_Linux_User 11.12.2014 / 15:35

3 respostas

3

Primeiro, você deve tentar determinar em qual iteração o problema ocorre. Se você tiver sorte, então é sempre o mesmo. Se você não fizer isso de qualquer maneira, deverá contar as iterações e imprimi-las ou gravá-las em um arquivo:

exec 3>/my/logfile
iter=0
while whatevercondition; do
  ((iter++))
  echo "$iter" >&3
done

Se o problema ocorrer sempre na mesma iteração, você deverá ativar a saída de depuração e, em seguida:

CRASH_ITER=12345
iter=0
while whatevercondition; do
  ((iter++))
  if [ "$iter" -eq "$CRASH_ITER" ]; then
    set -vx
  fi
done

erros não reprodutíveis

Se não for possível restringir o erro a uma certa iteração, você pode ter o bash gravando a saída de depuração completa em um arquivo:

bash -vx ./script.sh 2>debug.txt
    
por 11.12.2014 / 15:44
1

Se você adicionar isso ao topo do seu script bash:


   function DEBUG_TRAP() { 
      typeset -p BASH_SOURCE; typeset -p BASH_LINENO; typeset -p FUNCNAME
   }
   trap DEBUG_TRAP INT

você pode obter informações sobre onde o programa está enviando o processo a um sinal INT:

kill -INT process-number

Você pode obter o número do processo dentro do script bash da seguinte forma:

   echo $$

Se você não obtiver nenhuma saída depois de fazer isso, o script redirecionou a saída ou o script ficou suspenso em um processo. O lsof lhe dirá informações sobre o redirecionamento de saída, enquanto o ps fornecerá informações sobre o status do processo.

    
por 11.01.2015 / 02:29
0

Se o seu loop se parecesse com:

i=0
while [ "$((i+=1))" -le 5000 ] &&
      set >iter.log
do    monte_carlo
done

Você obteria um arquivo sobrescrito para cada iteração, listando os valores atuais de todas as variáveis do shell a cada vez. Então, se ele quebrar na corrida 488, você terá um arquivo iter.log que registrou o valor de $i como 488 e todas as outras variáveis do shell no início da iteração.

Para acompanhar o número da linha com falha, você pode ir um pouco além:

i=0 PS4='$LINENO : '; set -x
while [ ... ] &&
      set >iter.log
do    ...
done 2>>iter.log

Isso ainda sobrescreveria o arquivo para cada iteração, mas também acrescentaria a saída de depuração para cada linha executada e incluiria seu número de linha no arquivo.

    
por 11.01.2015 / 04:56