Трассировка выполненных программ, вызываемых скриптом Bash - PullRequest
19 голосов
/ 26 марта 2009

Скрипт плохо себя ведет. Мне нужно знать, кто вызывает этот сценарий, а кто вызывает вызывающий сценарий и т. Д., Только изменяя неверно работающий сценарий.

Это похоже на трассировку стека, но я не заинтересован в стеке вызовов функций внутри одного скрипта bash. Вместо этого мне нужна цепочка выполненных программ / скриптов, которая инициируется моим скриптом.

Ответы [ 8 ]

15 голосов
/ 17 сентября 2009

Простой скрипт, который я написал несколько дней назад ...

# FILE       : sctrace.sh
# LICENSE    : GPL v2.0 (only)
# PURPOSE    : print the recursive callers' list for a script
#              (sort of a process backtrace)
# USAGE      : [in a script] source sctrace.sh
#
# TESTED ON  :
# - Linux, x86 32-bit, Bash 3.2.39(1)-release

# REFERENCES:
# [1]: http://tldp.org/LDP/abs/html/internalvariables.html#PROCCID
# [2]: http://linux.die.net/man/5/proc
# [3]: http://linux.about.com/library/cmd/blcmdl1_tac.htm

#! /bin/bash

TRACE=""
CP=$$ # PID of the script itself [1]

while true # safe because "all starts with init..."
do
        CMDLINE=$(cat /proc/$CP/cmdline)
        PP=$(grep PPid /proc/$CP/status | awk '{ print $2; }') # [2]
        TRACE="$TRACE [$CP]:$CMDLINE\n"
        if [ "$CP" == "1" ]; then # we reach 'init' [PID 1] => backtrace end
                break
        fi
        CP=$PP
done
echo "Backtrace of '$0'"
echo -en "$TRACE" | tac | grep -n ":" # using tac to "print in reverse" [3]

... и простой тест.

test

Надеюсь, тебе понравится.

7 голосов
/ 24 марта 2014

Вы можете использовать Bash Debugger http://bashdb.sourceforge.net/

Или, как упоминалось в предыдущих комментариях, встроенный bash caller. Смотрите: http://wiki.bash -hackers.org / команды / встроенный / звонящий

i=0; while caller $i ;do ((i++)) ;done

Другой способ сделать это - изменить PS4 и включить xtrace:

PS4='+$(date "+%F %T") ${FUNCNAME[0]}() $BASH_SOURCE:${BASH_LINENO[0]}+ '
set -o xtrace    # Comment this line to disable tracing.
7 голосов
/ 26 марта 2009
~$ help caller
caller: caller [EXPR]
    Returns the context of the current subroutine call.

    Without EXPR, returns "$line $filename".  With EXPR,
    returns "$line $subroutine $filename"; this extra information
    can be used to provide a stack trace.

    The value of EXPR indicates how many call frames to go back before the
    current one; the top frame is frame 0.
6 голосов
/ 26 марта 2009

Поскольку вы говорите, что можете редактировать сам скрипт, просто введите:

ps -ef >/tmp/bash_stack_trace.$$

в нем, где возникает проблема.

В этом каталоге tmp будет создано несколько файлов, в которых будет показан весь список процессов в тот момент, когда это произошло.

Затем вы можете определить, какой процесс вызвал какой другой процесс, изучив этот вывод. Это можно сделать вручную или автоматизировать с помощью чего-то вроде awk, поскольку выходные данные являются регулярными - вы просто используете эти столбцы PID и PPID, чтобы установить отношения между всеми интересующими вас процессами.

Вам нужно будет следить за файлами, так как вы будете получать по одному на процесс, поэтому им, возможно, придется управлять. Так как это нужно делать только во время отладки, большую часть времени эта строка будет закомментирована (перед #), поэтому файлы не будут созданы.

Чтобы очистить их, вы можете просто сделать:

rm /tmp/bash_stack_trace.*
2 голосов
/ 18 сентября 2013

UPDATE: Код ниже должен работать. Теперь у меня есть более новый ответ с более новой версией кода, позволяющей вставить сообщение в трассировку стека.

IIRC Я просто не мог найти этот ответ, чтобы обновить его в то время. Но теперь решено, что код лучше хранить в git, поэтому последняя версия вышеупомянутого должна быть в этом gist .

оригинальный ответ с исправлением кода ниже:

Был другой ответ об этом где-то, но здесь есть функция, используемая для получения трассировки стека в том смысле, который используется, например, в языке программирования Java. Вы вызываете функцию, и она помещает трассировку стека в переменную $ STACK. Он показывает кодовые точки, которые привели к вызову get_stack. Это в основном полезно для сложного выполнения, когда одна оболочка получает несколько фрагментов сценария и вложенность.

function get_stack () {
   STACK=""
   # to avoid noise we start with 1 to skip get_stack caller
   local i
   local stack_size=${#FUNCNAME[@]}
   for (( i=1; i<$stack_size ; i++ )); do
      local func="${FUNCNAME[$i]}"
      [ x$func = x ] && func=MAIN
      local linen="${BASH_LINENO[(( i - 1 ))]}"
      local src="${BASH_SOURCE[$i]}"
      [ x"$src" = x ] && src=non_file_source

      STACK+=$'\n'"   "$func" "$src" "$linen
   done
}
0 голосов
/ 30 апреля 2019

Самый простой скрипт, который возвращает трассировку стека со всеми вызывающими:

i=0; while caller $i ;do ((i++)) ;done
0 голосов
/ 26 марта 2009

Вы можете попробовать что-то вроде

strace -f -e execve script.sh
0 голосов
/ 26 марта 2009

добавление вывода pstree -p -u `whoami` >> в ваш скрипт, вероятно, даст вам необходимую информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...