Bash-在脚本中记录所有命令和退出代码
我有一个很长的(~2000行)脚本,我正试图记录它以备将来调试。现在我有:Bash-在脚本中记录所有命令和退出代码,bash,logging,Bash,Logging,我有一个很长的(~2000行)脚本,我正试图记录它以备将来调试。现在我有: function log_with_time() { while read a; do echo `date +'%H:%M:%S.%4N '` " $a" >> $LOGFILE done } exec 7> >(log_with_time) BASH_XTRACEFD=7 PS4=' exit($?)ln:$LINENO: ' set -x echo "hel
function log_with_time()
{
while read a; do
echo `date +'%H:%M:%S.%4N '` " $a" >> $LOGFILE
done
}
exec 7> >(log_with_time)
BASH_XTRACEFD=7
PS4=' exit($?)ln:$LINENO: '
set -x
echo "helloWorld 1"
这使我能够很好地记录运行的所有命令:
15:18:03.6359 exit(0)ln:28: echo 'helloWorld 1'
我遇到的问题是xtrace似乎是异步的。对于较长的脚本,日志时间落后于调用命令的实际时间,并且退出代码与记录的命令不匹配
必须有更好的方法来做到这一点,但如果我能同步这场比赛,我会很高兴
tldr:如何记录脚本中所有命令的时间、命令和退出代码
(首次发布,欢迎反馈)
更新:
exec {BASH_XTRACEFD}>>$LOGFILE
PS4=' time:$(date +%H:%M:%S.%4N) ln:$LINENO: '
set -x
fail()
{
echo "fail" >> $LOGFILE
return 1
}
trap 'echo exit:$? >> $LOGFILE' DEBUG
fail
解决了我所有的同步问题。退出代码和时间戳运行良好。我的现在唯一的问题是格式化:陷阱本身被xtrace报告
time:18:30:07.6080 ln:27: fail
time:18:30:07.6089 ln:12: echo fail
fail
time:18:30:07.6126 ln:13: return 1
time:18:30:07.6134 ln:28: echo exit:1
exit:1
我曾尝试在陷阱中设置+x,但随后会记录set+x。如果我能找到一种方法从xtrace中省略一行,那么这个日志将是完美的。异步行为来自进程替换--
(…)
中的任何内容都在FIFO另一端的自己的子shell中运行。因为它是一个独立的过程,所以本质上是不同步的
不过,这里根本不需要log\u with_time
,因此首先不需要BASH\u XTRACEFD
重定向到流程替换。考虑:
# aside: $(date ...) has a *huge* amount of performance overhead here. Personally, I'd
# advise against using it, unless you really need all that precision; $SECONDS will
# be orders-of-magnitude cheaper.
PS4=' prior-exit:$? time:$(date +%H:%M:%S.%4N) ln:$LINENO: '
……此后:
$true
先前退出:0时间:16:01:17.2509 ln:28:正确
$false
先前退出:0时间:16:01:18.4242 ln:29:false
$false
提前退出:1时间:16:01:19.2963 ln:30:false
$true
先前退出:1时间:16:01:20.2159 ln:31:正确
$true
先前退出:0时间:16:01:20.8650 ln:32:正确
与Charles Duffy在评论中的每一次对话,所有评论均被授予:
进程替换>(…)是异步的,允许日志写入落后并与xtrace不同步。
而是使用:
exec {BASH_XTRACEFD}>>$LOGFILE
PS4=' time:$(date +%H:%M:%S.%4N) ln:$LINENO: '
trap 'echo exit:$? >> $LOGFILE' DEBUG
用于同步记录时间和线路
此外,在运行命令之前会触发xtrace,这使得它不适合捕获退出代码。而是使用:
exec {BASH_XTRACEFD}>>$LOGFILE
PS4=' time:$(date +%H:%M:%S.%4N) ln:$LINENO: '
trap 'echo exit:$? >> $LOGFILE' DEBUG
记录每个命令的退出代码,因为陷阱在命令完成时触发。注意,这不会像xtrace那样报告函数调用中的每个步骤。(这里的措辞需要一些帮助)
还没有从xtrace中省略陷阱的解决方案,但已经足够好了:
LOGFILE="SomeFile.log"
exec {BASH_XTRACEFD}>>$LOGFILE
PS4=' time:$(date +%H:%M:%S.%4N) ln:$LINENO: '
set -x
fail() # test function that returns 1
{
echo "fail" >> $LOGFILE
return 1
}
success() # test function that returns 0
{
echo "success" >> $LOGFILE
return 0
}
trap 'echo $? >> $LOGFILE' DEBUG
fail
success
echo "complete"
收益率:
time:14:10:22.2686 ln:21: trap 'echo $? >> $LOGFILE' DEBUG
time:14:10:22.2693 ln:23: echo 0
0
time:14:10:22.2736 ln:23: fail
time:14:10:22.2741 ln:12: echo fail
fail
time:14:10:22.2775 ln:13: return 1
time:14:10:22.2782 ln:24: echo 1
1
time:14:10:22.2830 ln:24: success
time:14:10:22.2836 ln:17: echo success
success
time:14:10:22.2873 ln:18: return 0
time:14:10:22.2881 ln:26: echo 0
0
time:14:10:22.2912 ln:26: echo complete
异步的是进程替换。
>(…)
中的任何内容都位于FIFO的另一端,在自己的进程中运行。对BASH\u XTRACEFD
的实际写入本身是完全同步的。无论如何,您不需要它——您可以设置一个插入日期本身的PS4
。。顺便说一句,作为一种风格说明--function funcname(){
是POSIX sh和古老的ksh声明约定的混合体(前者只是funcname()){
,第二个是函数funcname{
),两者都不兼容。最佳做法是选择一个或另一个——我强烈建议使用POSIX形式,因为bash的ksh式函数声明语法实际上与ksh中的格式没有相同的语义(默认情况下,它使函数中定义的变量成为本地变量)…顺便说一句,您可以做的另一件事就是通过相同的流程替换来指导其他所有内容。使事情有效地异步的原因是一些内容直接到达TTY(或者您先前存在的输出目标),其他则通过流程替换;如果所有内容都通过相同的管道,那么它将再次同步……另一方面,现代bash具有printf%(%H:%M:%s)T-1
发出当前时间,而不需要分叉子shell,然后使用exec
-family系统调用将该子shell替换为/usr/bin/date
(更不用说设置一对FIFO来读取该子shell的输出,&c)。在我的评论中格式化尝试失败后,我已更新我的答案以反映我的最新尝试。(顺便说一下,感谢您迄今为止的所有帮助)除了在某些情况下没有正确对齐之外,在可读性方面,previousexit实际上是不可接受的previousexit
也是您的原始代码所做的--我只是提供了一个更准确的标签。