2009-03-26 6 views
17

Scenariusz źle się spisuje. Muszę wiedzieć, kto dzwoni do tego skryptu i kto wywołuje skrypt wywołujący, i tak dalej, tylko modyfikując źle działający skrypt.Śledzenie wykonanych programów wywołanych skryptem bash

To jest podobne do śledzenia stosu, ale jestem nie zainteresowany stosem wywołań funkcji w jednym skrypcie basha. Zamiast tego potrzebuję łańcucha wykonanych programów/skryptów inicjowanych przez mój skrypt.

Odpowiedz

6

Skoro mówisz można edytować samego skryptu, wystarczy umieścić:

ps -ef >/tmp/bash_stack_trace.$$ 

w nim, w którym problem występuje.

Spowoduje to utworzenie wielu plików w katalogu tmp, które pokazują całą listę procesów w momencie jej wystąpienia.

Można następnie sprawdzić, który proces wywołał inny proces, analizując to wyjście. Można to zrobić albo ręcznie, lub automatycznie z czymś awk, ponieważ wyjście jest regularny. - po prostu użyć tych PID i PPID kolumny wypracować relacje między wszystkimi procesami, które Cię interesują

Będziesz musisz pilnować plików, ponieważ dostaniesz jeden na proces, więc może trzeba nim zarządzać. Ponieważ jest to coś, co powinno być zrobione tylko podczas debugowania, w większości przypadków ta linia zostanie skomentowana (poprzedzona #), więc pliki nie zostaną utworzone.

Aby oczyścić je, można po prostu zrobić:

rm /tmp/bash_stack_trace.* 
+0

nie jest to ślad stosu choć. w najlepszym razie byłby to ślad exec. Ale dla tego pstree -pal lub ps -ef --forest będzie lepiej nadaje się.
Nie pokazuje wywołania funkcji * stos *, ani nie pokazuje bieżącego pliku kodu i linii. Zwykle jest to cały punkt śledzenia stosu. – Evi1M4chine

+0

Tak, ale OP stwierdził, że chciał tylko wiedzieć, które skrypty nazywają skrypty, więc szczegóły na temat linii w skrypcie nie są konieczne. Po zapoznaniu się ze stosem exec można rozpocząć dodawanie instrukcji debugowania, takich jak 'set -x' do poszczególnych skryptów, aby uzyskać dokładniejsze śledzenie. – paxdiablo

+0

Nie uważam tego za odpowiedź na to pytanie, przynajmniej nie we wspólnym rozumieniu śladu stosu. – akostadinov

0

dodanie pstree -p -u ` whoami ` >> wyjścia w skrypcie będzie prawdopodobnie Ci potrzebne informacje.

6
~$ 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. 
+1

Podczas gdy i '-x' są użyteczne, brzmi to tak, jakby to nie pomogło OP, ponieważ działa to tylko w wywołaniach funkcji w tym samym skrypcie. – ephemient

+0

Zobacz odpowiedź Mircea Vutcovici powyżej. Ten ma rację, czego potrzebowałem: i = 0; while caller $ i; do ((++)), done –

-1

Można spróbować czegoś podobnego

strace -f -e execve script.sh 
14

prosty skrypt pisałem kilka dni temu ...

# 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] 

... i prosty test.

test

Mam nadzieję, że Ci się spodoba.

+0

To nie działa na Mac OS X. :(Nie, że twierdziłeś, że to zrobił, ale tylko dla tych, którzy szukają rozwiązania Mac, to nie jest to. –

+2

Tak, używa urządzeń linuksowych (pytanie było o Linux, mimo wszystko), przepraszam ... –

+2

to okazało się być co pracował dla mnie na Mac OS X i Linux(): natomiast rozmówca $ zrobić i = $ ((i + 1)) zrobione –

2

AKTUALIZACJA: Poniższy kod powinien działać. Teraz znalazłem, że mam newer answer z nowszą wersją kodu, która pozwala na umieszczenie wiadomości w stosie stacktrace.

IIRC Po prostu nie mogłem znaleźć tej odpowiedzi, aby zaktualizować ją również w tym czasie. Ale teraz zdecydowany kod jest lepiej trzymany w git, więc najnowsza wersja powyższego powinna być w tym gist.

oryginalny kod korekcją odpowiedź poniżej:

Była inna odpowiedź o tym gdzieś, ale tutaj jest funkcją użyć do uzyskania ślad stosu w tym sensie, wykorzystywany na przykład w języku programowania Java. Wywołujesz funkcję i umieszcza ślad stosu w zmiennej $ STACK. Pokazuje punkty kodowe, które doprowadziły do ​​wywołania get_stack. Jest to szczególnie przydatne w przypadku skomplikowanego wykonywania, w którym pojedyncze powłoki zawierają wiele fragmentów kodu i zagnieżdżanie.

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

Przydatny fragment kodu na początek, ale ma błędy. na przykład $ {# FUNCNAME [1]} jest długością pierwszej nazwy funkcji, a nie liczbą wpisów w tablicy FUNCNAME, a "i - 1" dla lineno wydaje się błędne. – Eric

+0

@Eric, dziękuję, pamiętam, że wykonałem kilka poprawek w mojej wersji produkcyjnej, których nie mogę znaleźć, ponieważ przestałem używać tego przedmiotu dawno temu. I niestety przegapiłem aktualizację kodu tutaj. Naprawiłem 'stack_size'. LINENO wygląda mi na poprawny z prostego testu lokalnego, daj mi znać, jeśli to nie działa. Pamiętam też różnicę z 'stack_size' podczas uruchamiania skryptu z pliku vs wywoływania jakiejś funkcji z interaktywnej powłoki. Myślę, że można go automatycznie odgadnąć, ale nie ma czasu na zabawę. tzn. w trybie interaktywnym potrzebujesz 'stack_size + 1'. – akostadinov

+0

@Eric, dzięki tobie i ja możemy ostatecznie połączyć moje dwie odpowiedzi na ten temat. Zobacz aktualizację powyżej. Zapraszam do współpracy nad istotą. Myślę, że poprawa polegałaby na automatycznym wykrywaniu, kiedy potrzebujemy zatrzymać się w 'stack_size' lub' stack_size + 1'. – akostadinov

6

Można użyć Bash Debugger http://bashdb.sourceforge.net/

Albo, jak wspomniano w poprzednich komentarzach, na caller bash wbudowane. Zobacz: http://wiki.bash-hackers.org/commands/builtin/caller

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

Innym sposobem, aby to zrobić jest zmiana PS4 i umożliwić xtrace:

PS4='+$(date "+%F %T") ${FUNCNAME[0]}() $BASH_SOURCE:${BASH_LINENO[0]}+ ' 
set -o xtrace # Comment this line to disable tracing. 
+2

Szczególnie podoba mi się ten: i = 0; while caller $ i; do ((i ++)), done –

+0

Najlepsza odpowiedź! –

Powiązane problemy