Acho que o problema é que você espera que "$LINENO"
forneça a linha de execução do último comando, o que pode funcionar quase, mas clean_a()
também obtém seu próprio $LINENO
e que você deve fazer em vez disso:
error "something!
line: $1
...
Mas mesmo isso provavelmente não funcionaria porque espero que seja apenas imprimir a linha na qual você definiu o trap
.
Aqui está uma pequena demonstração:
PS4='DEBUG: $LINENO : ' \
bash -x <<\CMD
trap 'fn "$LINENO"' EXIT
fn() { printf %s\n "$LINENO" "$1"; }
echo "$LINENO"
CMD
OUTPUT
DEBUG: 1 : trap 'fn "$LINENO"' EXIT
DEBUG: 3 : echo 3
3
DEBUG: 1 : fn 1
DEBUG: 2 : printf '%s\n' 2 1
2
1
Portanto, o trap
é definido e, em seguida, fn()
é definido e, em seguida, echo
é executado. Quando o shell conclui a execução de sua entrada, o EXIT
trap é executado e fn
é chamado. É passado um argumento - que é o trap
da linha $LINENO
. fn
imprime primeiro seu próprio $LINENO
, em seguida, seu primeiro argumento.
Posso pensar em uma maneira de obter o comportamento esperado, mas isso estraga ostderr
:
PS4='DEBUG: $((LASTNO=$LINENO)) : ' \
bash -x <<\CMD
trap 'fn "$LINENO" "$LASTNO"' EXIT
fn() { printf %s\n "$LINENO" "$LASTNO" "$@"; }
echo "$LINENO"
CMD
OUTPUT
DEBUG: 1 : trap 'fn "$LINENO" "$LASTNO"' EXIT
DEBUG: 3 : echo 3
3
DEBUG: 1 : fn 1 3
DEBUG: 2 : printf '%s\n' 2 1 1 3
2
1
1
3
Ele usa o prompt de depuração $PS4
do shell para definir $LASTNO
em cada linha executada. É uma variável de shell atual que você pode acessar em qualquer lugar dentro do script. Isso significa que não importa qual linha está sendo acessada atualmente, você pode fazer referência à linha mais recente do script executada em $LASTNO
. Claro, como você pode ver, vem com saída de depuração. Você pode enviar isso para 2>/dev/null
para a maioria da execução do script, e apenas 2>&1
em clean_a()
ou algo assim.
O motivo pelo qual você obtém 1
em $LASTNO
é porque esse é o último valor para o qual $LASTNO
foi definido porque esse foi o último valor $LINENO
. Você tem seu trap
na função archieve_it()
e, portanto, ele recebe seu próprio $LINENO
, como é indicado na especificação abaixo. Embora não pareça que bash
faz a coisa certa de qualquer maneira, também pode ser porque o trap
tem que reexecutar o shell em INT
signal e $LINENO
é, portanto, redefinido. Estou um pouco confuso sobre isso neste caso - como é bash
, aparentemente.
Você não quer avaliar $LASTNO
em clean_a()
, eu acho. Melhor seria avaliá-lo no trap
e passar o valor trap
recebe em $LASTNO
até clean_a()
como argumento. Talvez assim:
#!/bin/bash
PS4='^MDEBUG: $((LASTNO=$LINENO)) : '; set -x
archieve_it () {
trap 'clean_a $LASTNO $LINENO "$BASH_COMMAND"' \
SIGHUP SIGINT SIGTERM SIGQUIT
while :; do sleep 1; done
} 2>/dev/null
clean_a () { : "$@" ; } 2>&1
Tente isso - ele deve fazer o que você quiser, eu acho. Ah - e note que em PS4=^M
o ^M
é um retorno literal - como CTRL + V ENTER.
Da especificação de shell POSIX :
Set by the shell to a decimal number representing the current sequential line number (numbered starting with 1) within a script or function before it executes each command. If the user unsets or resets
LINENO
, the variable may lose its special meaning for the life of the shell. If the shell is not currently executing a script or function, the value ofLINENO
is unspecified. This volume of IEEE Std 1003.1-2001 specifies the effects of the variable only for systems supporting the User Portability Utilities option.