En lugar de usar su función, usaría este método:
$ cat yael.bash
#!/bin/bash
set -eE -o functrace
file1=f1
file2=f2
file3=f3
file4=f4
failure() {
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
cp -- "$file1" "$file2"
cp -- "$file3" "$file4"
Esto funciona capturando ERR y luego llamando al failure()
función con el número de línea actual + comando bash que se ejecutó.
Ejemplo
Aquí no me he preocupado por crear los archivos, f1
, f2
, f3
, o f4
. Cuando ejecuto el script anterior:
$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
Falla, informando el número de línea más el comando que se ejecutó.
Además de LINENO
que contiene el número de línea actual, están los BASH_LINENO
y FUNCNAME
(y BASH_SOURCE
) matrices que contienen los nombres de las funciones y los números de línea desde los que se llaman.
Así que podrías hacer algo como esto:
#!/bin/bash
error() {
printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}
foo() {
( exit 0 ) || error "this thing"
( exit 123 ) || error "that thing"
}
foo
Ejecutar eso imprimiría
'that thing' failed with exit code 123 in function 'foo' at line 9.
Si usa set -e
o trap ... ERR
para detectar errores automáticamente, tenga en cuenta que tienen algunas advertencias. También es más difícil incluir una descripción de lo que estaba haciendo la secuencia de comandos en ese momento (como hizo en su ejemplo), aunque eso podría ser más útil para un usuario normal que solo el número de línea.
Véase, por ejemplo. estos para los problemas con set -e
y otros:
- ¿Por qué set -e no funciona dentro de subcapas con paréntesis () seguido de una lista OR ||?
- bash -e sale cuando let o expr se evalúa como 0
- BashFAQ 105:¿Por qué set -e (o set -o errexit, o trap ERR) no hace lo que esperaba?
Bash tiene una variable incorporada $LINENO
que se reemplaza por el número de línea actual cuando está en una declaración, por lo que puede hacer
in_case_fail $? "at $LINENO: cp $file1 $file2"
También puedes intentar usar trap ... ERR
que se ejecuta cuando falla un comando (si el resultado no se prueba). Por ejemplo:
trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
Entonces, si un comando como cp $file1 $file2
falla obtendrá el mensaje de error con el número de línea y una salida. También encontrará el comando erróneo en la variable $BASH_COMMAND
(aunque no redirecciones, etc.).