Каждый процесс имеет ряд переменных среды (который может быть установлен в оболочке export SOMEVAR=value
и так). Они наследованы как есть дочерними процессами. Если Вы хотите сбросить их, использовать extern char **environ;
достигать переданную среду (см. environ(7)
), и затем используйте execle(3)
или execve(3)
передача новой среды выстраивает со скопированными значениями переменных. Некоторое руководство на том, что и то, как действительно делают это, дано David Wheeler в его "Безопасном ПРАКТИЧЕСКОМ РУКОВОДСТВЕ программирования Unix/Linux"
Думаю, проблема в том, что вы ожидаете, что "$ LINENO"
выдаст вам строку выполнения для последнего команда, которая может почти работать, но clean_a ()
также получает свою собственную $ LINENO
, которую вы должны использовать вместо этого:
error "something!
line: $1
...
Но даже это, вероятно, не сработает потому что я ожидаю, что он просто напечатает строку, в которой вы установили ловушку
.
Вот небольшая демонстрация:
PS4='DEBUG: $LINENO : ' \
bash -x <<\CMD
trap 'fn "$LINENO"' EXIT
fn() { printf %s\\n "$LINENO" "$1"; }
echo "$LINENO"
CMD
DEBUG: 1 : trap 'fn "$LINENO"' EXIT
DEBUG: 3 : echo 3
3
DEBUG: 1 : fn 1
DEBUG: 2 : printf '%s\n' 2 1
2
1
Итак, ловушка
устанавливается, затем определяется fn ()
, затем echo
выполнен. Когда оболочка завершает выполнение своего ввода, запускается ловушка EXIT
и вызывается fn
. Ему передается один аргумент - trap
строка $ LINENO
. fn
сначала выводит свой собственный $ LINENO
, а затем свой первый аргумент.
Я могу придумать один способ добиться ожидаемого поведения, но он как бы портит stderr
оболочки:
PS4='DEBUG: $((LASTNO=$LINENO)) : ' \
bash -x <<\CMD
trap 'fn "$LINENO" "$LASTNO"' EXIT
fn() { printf %s\\n "$LINENO" "$LASTNO" "$@"; }
echo "$LINENO"
CMD
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
Он использует $ PS4
оболочки. ] приглашение отладки для определения $ LASTNO
в каждой выполняемой строке. Это текущая переменная оболочки, к которой вы можете получить доступ в любом месте сценария. Это означает, что независимо от того, к какой строке в данный момент осуществляется доступ, вы можете ссылаться на самую последнюю строку запущенного скрипта в $ LASTNO
. Конечно, как вы можете видеть, он идет с выводом отладки. Вы можете нажать это на 2> / dev / null
, возможно, для большей части выполнения скрипта, а затем просто 2> & 1
в clean_a ()
или что-то в этом роде .
Причина, по которой вы получаете 1
в $ LASTNO
, заключается в том, что является последним значением, на которое было установлено $ LASTNO
, потому что это было последним значением $ LINENO
. У вас есть ловушка
в функции archieve_it ()
, поэтому она получает свою собственную $ LINENO
, как указано в спецификации ниже. Хотя не похоже, что bash
в любом случае делает там правильные вещи, так что это также может быть связано с тем, что ловушка
должна повторно запустить оболочку на INT
signal и $ LINENO
, следовательно, сбрасывается. Я немного не уверен в этом в данном случае - как, по-видимому, bash
.
Я думаю, вы не хотите оценивать $ LASTNO
в clean_a ()
. Лучше было бы оценить его в ловушке
и передать значение , которое ловушка
получает в $ LASTNO
, через clean_a ()
в качестве аргумента. . Может быть так:
#!/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
Попробуй - я думаю, он должен делать то, что ты хочешь. Да, и обратите внимание, что в PS4 = ^ M
^ M
является буквальным возвратом, как CTRL + V ENTER.
Из спецификации оболочки POSIX :
Устанавливается оболочкой в десятичное число, представляющее текущий последовательный номер строки (пронумерованный, начиная с 1) в сценарии или функции перед выполнением каждой команды. Если пользователь сбрасывает или сбрасывает
LINENO
, переменная может потерять свое особое значение на время жизни оболочки. Если оболочка в настоящее время не выполняет сценарий или функцию, значениеLINENO
не указано. Этот том IEEE Std 1003.1-2001 определяет эффекты переменной только для систем, поддерживающих опцию User Portability Utilities.
Решение mikeserv хорошее, но он не прав в том, что fn
передается строке trap
$LINENO
при выполнении ловушки. Вставьте строку перед trap ...
и вы увидите, что fn
на самом деле всегда передается 1
, независимо от того, где была объявлена ловушка.
PS4='DEBUG: $LINENO : ' \
bash -x <<\EOF
echo Foo
trap 'fn "$LINENO"' EXIT
fn() { printf %s\\n "$LINENO" "$1"; }
echo "$LINENO"
exit
EOF
DEBUG: 1 : echo Foo
Foo
DEBUG: 2 : trap 'fn "$LINENO"' EXIT
DEBUG: 4 : echo 4
4
DEBUG: 5 : exit
DEBUG: 1 : fn 1
DEBUG: 3 : printf '%s\n' 3 1
3
1
Поскольку первый аргумент ловушки, fn "$LINENO"
, заключен в одинарные кавычки, $LINENO
получает расширение, если и только когда EXIT сработал и поэтому должен расшириться до fn 5
. Так почему же этого не происходит? На самом деле так и было, вплоть до bash-4.0, когда он был намеренно изменен таким образом, что $LINENO сбрасывается в 1, когда срабатывает ловушка, и поэтому расширяется до fn 1
. [источник] Однако для ловушек ERR сохраняется оригинальное поведение, вероятно, потому что часто что-то вроде trap 'echo "Error at line $LINENO"'. ERR
используется.
#!/bin/bash
trap 'echo "exit at line $LINENO"' EXIT
trap 'echo "error at line $LINENO"' ERR
false
exit 0
error at line 5
exit at line 1
проверено с GNU bash, версия 4.3.42(1)-release (x86_64-pc-linux-gnu)
Получение LINENO = 0
вместо фактического номера строки при выходе из скрипта можно исправить, перехвативERR
(вместоEXIT
).
Кроме того, добавьте set -E
, чтобы гарантировать, что эти ловушки ERR наследуются функциями, подстановками команд и средами подоболочек. Например, вот как напечатать имя функции, вызвавшей ошибку скрипта, и номер ее строки:
set -eE
trap 'echo "Error in function $FUNCNAME at line $LINENO"' ERR
Кредиты:https://citizen428.net/blog/bash-error-handling-with-trap/
это должно подойти для более поздних версий bash:
trap 'debug_line_old=$debug_line;debug_line=$LINENO' DEBUG
trap 'catch echo EXIT rc=$? line=$debug_line_old' EXIT