2009-03-26 20 views
17

Một tập lệnh không đúng. Tôi cần phải biết ai gọi kịch bản đó và ai gọi kịch bản gọi điện, và cứ thế, chỉ bằng cách sửa đổi kịch bản sai.Dấu vết của các chương trình được thực hiện được gọi là bash script

Điều này tương tự như theo dõi ngăn xếp, nhưng tôi không phải quan tâm đến một cuộc gọi hàm gọi trong một tập lệnh bash đơn. Thay vào đó, tôi cần chuỗi các chương trình/tập lệnh được thực hiện do tập lệnh của tôi khởi xướng.

Trả lời

6

Vì bạn nói rằng bạn có thể chỉnh sửa kịch bản riêng của mình, chỉ cần đặt một:

ps -ef >/tmp/bash_stack_trace.$$ 

trong nó, nơi mà vấn đề đang xảy ra.

Thao tác này sẽ tạo một số tệp trong thư mục tmp hiển thị toàn bộ danh sách quy trình tại thời điểm xảy ra.

Sau đó, bạn có thể tìm ra quy trình nào được gọi là quy trình nào khác bằng cách kiểm tra đầu ra này. Đây một trong hai có thể được thực hiện bằng tay, hoặc tự động với một cái gì đó giống như awk, kể từ khi đầu ra là thường xuyên -. Bạn chỉ cần sử dụng những PIDPPID cột để làm việc ra các mối quan hệ giữa tất cả các quá trình bạn đang quan tâm đến

Bạn sẽ cần phải theo dõi các tệp, vì bạn sẽ nhận được một tệp cho mỗi quá trình để chúng có thể được quản lý. Vì đây là cái gì đó chỉ nên được thực hiện trong quá trình gỡ lỗi, phần lớn thời gian mà dòng đó sẽ được nhận xét (trước bởi #), vì vậy các tệp sẽ không được tạo.

Để làm sạch chúng lên, bạn chỉ có thể làm:

rm /tmp/bash_stack_trace.* 
+0

Đó không phải là một vết đống mặc dù. lúc tốt nhất nó sẽ là một dấu vết exec. Nhưng cho rằng pstree -pal hoặc ps -ef --forest sẽ phù hợp hơn.
Nó không hiển thị cuộc gọi chức năng * ngăn xếp *, cũng như không hiển thị tệp và dòng mã hiện tại. Đó thường là toàn bộ điểm của một dấu vết ngăn xếp. – Evi1M4chine

+0

Có nhưng OP cho biết họ chỉ muốn biết tập lệnh nào sẽ gọi tập lệnh nào, vì vậy chi tiết về dòng nào trong các tập lệnh là không cần thiết. Một khi bạn biết exec-stack, bạn có thể bắt đầu thêm các câu lệnh debug như 'set -x' vào các script riêng lẻ để có một dấu vết chi tiết hơn. – paxdiablo

+0

Tôi không coi đây là câu trả lời cho câu hỏi, ít nhất là không theo ý nghĩa của dấu vết ngăn xếp. – akostadinov

0

thêm pstree -p -u ` whoami ` >> đầu ra trong kịch bản của bạn có thể sẽ giúp bạn có được những thông tin bạn cần.

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

Trong khi điều này và '-x' là hữu ích, có vẻ như nó sẽ không giúp OP, vì điều này chỉ hoạt động trên các cuộc gọi hàm trong cùng một tập lệnh. – ephemient

+0

Xem câu trả lời của Mircea Vutcovici ở trên. Điều này là đúng những gì tôi cần: i = 0; trong khi người gọi $ i, làm ((i ++)), thực hiện –

-1

Bạn có thể thử một cái gì đó giống như

strace -f -e execve script.sh 
14

Một kịch bản đơn giản, tôi đã viết một số ngày trước ...

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

... và một thử nghiệm đơn giản.

test

Tôi hy vọng bạn thích nó.

+0

Điều này không hoạt động trên Mac OS X.: (Không phải bạn đã xác nhận nó, nhưng chỉ dành cho những người đang tìm kiếm giải pháp Mac, đây không phải là nó. –

+2

Có, nó sử dụng các thiết bị Linux (sau này là về Linux), xin lỗi ... –

+2

Điều này đã kết thúc với những gì đã làm việc cho tôi trên Mac OS X (và Linux): trong khi người gọi $ i do i = $ ((i + 1)) thực hiện –

2

CẬP NHẬT: Mã bên dưới sẽ hoạt động. Bây giờ tôi tìm thấy tôi có một newer answer với một phiên bản mã mới hơn cho phép một thông điệp được chèn vào trong stacktrace.

IIRC Tôi không thể tìm thấy câu trả lời này để cập nhật nó tại thời điểm đó. Nhưng bây giờ quyết định mã là tốt hơn giữ trong git vì vậy phiên bản mới nhất của các bên trên nên được trong này gist.

gốc câu trả lời mã chỉnh dưới đây:

Có một câu trả lời về nơi này, nhưng đây là một chức năng để sử dụng cho việc stack trace theo nghĩa sử dụng ví dụ như trong các ngôn ngữ lập trình java. Bạn gọi hàm và nó đặt dấu vết ngăn xếp vào biến $ STACK. Nó hiển thị các điểm mã dẫn đến số get_stack đang được gọi. Điều này chủ yếu là hữu ích cho việc thực hiện phức tạp, trong đó các trình bao duy nhất chứa nhiều đoạn mã và lồng nhau.

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

Mã bit hữu ích để bắt đầu, nhưng nó có lỗi. ví dụ. $ {# FUNCNAME [1]} là độ dài của tên hàm đầu tiên không phải là số mục nhập trong mảng FUNCNAME và "i - 1" cho lineno có vẻ sai. – Eric

+0

@Eric, cảm ơn bạn, tôi nhớ đã làm một số điều chỉnh trong phiên bản sản xuất của mình mà tôi không thể tìm thấy nữa vì tôi đã ngừng sử dụng từ lâu. Và tiếc là đã bỏ lỡ cập nhật mã ở đây. Tôi đã sửa 'stack_size'. LINENO có vẻ đúng với tôi từ một bài kiểm tra địa phương đơn giản, cho tôi biết nếu nó không hoạt động cho bạn. Tôi cũng nhớ một sự khác biệt với 'stack_size' khi chạy tập lệnh từ tập tin vs gọi một số chức năng từ trình bao tương tác. Tôi nghĩ rằng nó có thể được thực hiện tự động đoán nó nhưng không có thời gian để chơi với nó ngay bây giờ. tức là trong tương tác, bạn cần 'stack_size + 1'. – akostadinov

+0

@Eric, cảm ơn bạn và cuối cùng tôi có thể liên kết hai câu trả lời của tôi về chủ đề này. Xem cập nhật ở trên. Cảm thấy hoan nghênh cộng tác trên ý chính. Tôi nghĩ rằng một sự cải tiến sẽ được tự động cảm nhận khi chúng ta cần dừng lại ở 'stack_size' hoặc' stack_size + 1'. – akostadinov

6

Bạn có thể sử dụng Bash Debugger http://bashdb.sourceforge.net/

Hoặc, như đã đề cập trong các ý kiến ​​trước, caller bash built-in. Xem: http://wiki.bash-hackers.org/commands/builtin/caller

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

Một cách khác để làm điều đó là để thay đổi PS4 và cho phép xtrace:

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

Tôi đặc biệt thích cái này: i = 0; trong khi người gọi $ i; làm ((i ++)); được thực hiện –

+0

Câu trả lời hay nhất! –

Các vấn đề liên quan