Como mostrar o número da linha ao executar o script bash

89

Eu tenho um script de teste que tem muitos comandos e irá gerar muitas saídas, eu uso set -xou set -ve set -e, então o script iria parar quando ocorrer um erro. No entanto, ainda é bastante difícil para mim localizar qual linha interrompeu a execução para localizar o problema. Existe um método que pode produzir o número da linha do script antes de cada linha ser executada? Ou exibir o número da linha antes da exibição do comando gerado por set -x? Ou qualquer método que possa lidar com meu problema de localização de linha de script seria de grande ajuda. Obrigado.

dspjm
fonte

Respostas:

161

Você mencionou que já está usando -x. A variável PS4denota que o valor é o prompt impresso antes da linha de comando ser exibida quando a -xopção é definida e o padrão é :seguido por espaço.

Você pode alterar PS4para emitir o LINENO(O número da linha no script ou função shell atualmente em execução).

Por exemplo, se o seu script for:

$ cat script
foo=10
echo ${foo}
echo $((2 + 2))

Executá-lo, portanto, imprimiria números de linha:

$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4

http://wiki.bash-hackers.org/scripting/debuggingtips oferece o máximo PS4que produziria tudo o que você possivelmente precisará para rastrear:

export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
Devnull
fonte
4
Eu me pergunto por que ninguém menciona isso em "Como depurar scripts de shell?" . Isso é muito melhor do que apenasecho
Suvarna Pattayil
@VusP Concordo, echoé melhor evitar declarações desnecessárias .
devnull de
2
Não posso deixar de sentir que -x deveria imprimir números de linha. Ou, talvez - nx deve incluir números de linha. Para mim, é um daqueles momentos "WTF" ...
jww
1
Cara, eu gostaria de saber sobre aquela mistura do PS4 mais cedo ... Isso teria me salvado de tantas dores de cabeça
niken
2
\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'para algumas cores
Ulysse BN
35

No Bash, $LINENOcontém o número da linha onde o script está sendo executado atualmente.

Se você precisa saber o número da linha onde a função foi chamada, tente $BASH_LINENO . Observe que essa variável é uma matriz.

Por exemplo:

#!/bin/bash       

function log() {
    echo "LINENO: ${LINENO}"
    echo "BASH_LINENO: ${BASH_LINENO[*]}"
}

function foo() {
    log "$@"
}

foo "$@"

Veja aqui os detalhes das variáveis ​​Bash.

Deqing
fonte
0

Solução simples (mas poderosa): Coloque em echovolta do código que você acha que está causando o problema e mova echolinha por linha até que as mensagens não apareçam mais na tela - porque o script parou devido a um erro anterior.

Solução ainda mais poderosa: Instale bashdbo depurador bash e depure o script linha por linha

hek2mgl
fonte
2
echomanipular coisas pode ajudar em muitos casos, mas é insuficiente quando você tenta aplicá-las em funções que têm saída significativa e analisável.
Eliran Malka,
1
@EliranMalka Fair point. Você pode ecoar para stderr neste caso:echo "foo" >&2
hek2mgl
1
... deve-se ecoar para stderr em todos os casos quando o objetivo são mensagens de diagnóstico por natureza.
Charles Duffy
0

Solução alternativa para shells sem LINENO

Em um script bastante sofisticado, não gostaria de ver todos os números de linha; em vez disso, gostaria de estar no controle da saída.

Defina uma função

echo_line_no () {
    grep -n "$1" $0 |  sed "s/echo_line_no//" 
    # grep the line(s) containing input $1 with line numbers
    # replace the function name with nothing 
} # echo_line_no

Use-o com citações como

echo_line_no "this is a simple comment with a line number"

A saída é

16   "this is a simple comment with a line number"

se o número desta linha no arquivo de origem for 16.

Basicamente, isso responde à pergunta Como mostrar o número da linha ao executar o script bash para usuários do ash ou de outros shells sem LINENO.

Mais alguma coisa a acrescentar?

Certo. Por que você precisa disso? Como você trabalha com isso? O que você pode fazer com isso? Esta abordagem simples é realmente suficiente ou útil? Por que você quer mexer nisso tudo?

Quer saber mais? Leia as reflexões sobre depuração

kklepper
fonte