我有一个bash
脚本需要将近 5 秒才能运行。我想调试它,并确定哪些命令花费的时间最长。这样做的最佳方法是什么?有我可以设置的标志吗?设置#!/bin/bash -vx
并没有真正帮助。我想要的基本上是按行号的执行时间。
问问题
3793 次
4 回答
24
这与内置 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
于 2014-12-19T03:03:46.847 回答
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
于 2013-08-04T04:50:57.953 回答
2
尝试这个:
sed 's/^\([^#]\)/time \1/' script.sh>tmp.sh && ./tmp.sh
它在所有非命令行前添加时间命令
于 2013-08-04T04:58:52.810 回答
2
您可以使用set -x
让脚本在执行之前打印每个命令。我不知道自动添加命令计时的方法。您可以date
在整个脚本中添加命令来标记时间。
于 2013-08-04T04:40:25.107 回答