如何调试bash脚本并获得每个命令的执行时间

时间:2013-08-04 04:36:24

标签: linux bash

我有一个bash脚本,需要将近5秒才能运行。我想调试它,并确定哪些命令花费的时间最长。这样做的最佳方式是什么?我可以设置一个标志吗?设置#!/bin/bash -vx并没有多大帮助。我想要的基本上是按行号执行时间。

4 个答案:

答案 0 :(得分:17)

这是尽可能接近内置bash调试工具的答案,因为它提供了脚本执行开始时间的整体时序信息。

在脚本的顶部添加此内容以进行第二次计数:

export PS4='+[${SECONDS}s][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x;

相同,但用毫秒代替:

N=`date +%s%N`; export PS4='+[$(((`date +%s%N`-$N)/1000000))ms][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x;

最后一个例子可以达到微秒精度,请记住你正在使用bash :)。

示例脚本:

#!/bin/bash
N=`date +%s%N`
export PS4='+[$(((`date +%s%N`-$N)/1000000))ms][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x;
sleep 1
exit

示例调试输出:

+[3ms][/root/db_test.sh:5]: sleep 1
+[1012ms][/usr/local/bin/graphite_as_rand_stat.sh:6]: exit

请注意,您可以通过将脚本封装在' set -x'中来有选择地调试脚本的特定部分。在调试开始和' debug + x'在调试结束。从执行开始,计时数据仍会正确显示。

<强>附录

为了完整起见,如果您确实需要差分计时数据,您可以将调试信息重定向到文件并在之后进行处理。

给出这个示例脚本:

#!/bin/bash
N=`date +%s%N`
export PS4='+[$(((`date +%s%N`-$N)/1000000))ms][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x;
sleep 1
for ((i=0;i<2;i++)); do
        o=$(($RANDOM*$RANDOM/$RANDOM))
        echo $o
        sleep 0.$o
done
exit

将调试重定向到文件时运行它:

./example.sh 2>example.dbg

用此输出差分调试时序(涵盖多行):

p=0; cat example.dbg | while read l; do [[ ! ${l%%[*} =~ ^\+ ]] && echo $l && continue; i=`echo $l | sed 's#[^0-9]*\([0-9]\+\).*#\1#'`; echo $l | sed "s#${i}ms#${i}ms+$(($i-$p))ms#"; p=$i; done

输出:

+[2ms+2ms][./example.sh:5]: sleep 1
+[1006ms+1004ms][./example.sh:6]: (( i=0 ))
+[1009ms+3ms][./example.sh:6]: (( i<2 ))
+[1011ms+2ms][./example.sh:7]: o=19258
+[1014ms+3ms][./example.sh:8]: echo 19258
+[1016ms+2ms][./example.sh:9]: sleep 0.19258
+[1213ms+197ms][./example.sh:6]: (( i++ ))
+[1217ms+4ms][./example.sh:6]: (( i<2 ))
+[1220ms+3ms][./example.sh:7]: o=176
+[1226ms+6ms][./example.sh:8]: echo 176
+[1229ms+3ms][./example.sh:9]: sleep 0.176
+[1442ms+213ms][./example.sh:6]: (( i++ ))
+[1460ms+18ms][./example.sh:6]: (( i<2 ))
+[1502ms+42ms][./example.sh:11]: exit

答案 1 :(得分:6)

您可以使用time实用程序来衡量各个命令/功能的运行时间。

例如:

[ben@imac ~]$ cat times.sh
#!/bin/bash

test_func ()
{
    sleep 1
    echo "test"
}

echo "Running test_func()"
time test_func
echo "Running a 5 second external command"
time sleep 5

运行该脚本会产生以下内容:

[ben@imac ~]$ ./times.sh
Running test_func()
test

real    0m1.003s
user    0m0.001s
sys     0m0.001s
Running a 5 second external command

real    0m5.002s
user    0m0.001s
sys     0m0.001s

答案 2 :(得分:2)

您可以使用set -x让脚本在执行之前打印每个命令。我不知道如何自动添加命令时序。您可以在整个脚本中添加date命令来标记时间。

答案 3 :(得分:1)

试试这个:

sed 's/^\([^#]\)/time \1/' script.sh>tmp.sh && ./tmp.sh

它为所有非命令行添加时间命令