Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash-在脚本中记录所有命令和退出代码_Bash_Logging - Fatal编程技术网

Bash-在脚本中记录所有命令和退出代码

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

我有一个很长的(~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 "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
也是您的原始代码所做的--我只是提供了一个更准确的标签。