如何解决捕获一行代码的错误流,并使用trap报告错误流,同时保持标准输出不变 很快再走一步完整可用版本
我在下面的2个Shell脚本中尝试了以下(简化的)代码。
该脚本调用一个R脚本,在该脚本中运行代码,这将根据发生的情况生成标准输出和错误流。
我要实现的是照常在控制台上同时显示输出和错误流,但是当脚本运行且失败时(例如RScript产生错误流),我想保存该错误消息R在sqlite数据库中生成,但仍具有正常输出,并且退出时控制台上也会显示错误。我已经尝试了多种形式的Rscript函数的输出重定向,但是我要么最终没有将任何东西保存到数据库中(除了行号),要么我可以保存错误消息,但是控制台上什么也不会放置... >
这不会将错误消息保存到数据库(行号会),但是所有内容都将在控制台上
updateDBwhenError() {
sqlite3 "myDB.db" "INSERT INTO logs VALUES('$1')"
}
err_report() {
#Tryign to capture both line error and message
updateDBwhenError "Error Line $1 $2"
exit
}
trap 'err_report ${LINENO}' ERR
Rscript testScript.R
updateDBwhenError() {
sqlite3 "myDB.db" "INSERT INTO logs VALUES('$1')"
}
err_report() {
#Tryign to capture both line error and message
updateDBwhenError "Error Line $1 $rErr"
exit
}
trap 'err_report ${LINENO}' ERR
rErr=$(Rscript testScript.R 2>&1)
我到处寻找一种方法来仅捕获错误流到变量并保持控制台上的输出不变(输出和错误),但是我被困住了:)
Grtz, PJ
解决方法
尝试一下
exec 5>&1
exec 6>&1
rErr=$(Rscript testScript.R 2>&1 1>&6 | tee /dev/fd/5)
测试脚本
$ cat test
#!/bin/bash
ls
ls sdfgds
使用此脚本进行测试
$ exec 5>&1
$ exec 6>&1
$ err=$(./test 2>&1 1>&6 | tee /dev/fd/5)
file new_file test xml
ls: cannot access 'sdfgds': No such file or directory
$ echo "$err"
ls: cannot access 'sdfgds': No such file or directory
,
很快
使用未命名的fifos (警告,因为OS会进行缓冲,所以这将起作用,因此仅当输出保持在64Kb以下时才可以使用!),这是一种微妙的bash方式:
exec {HOLDERR}<> <(:)
ls -ld /t{mp,nt} 2>&${HOLDERR}
read -t 0 -u $HOLDERR && read -ru $HOLDERR errmsg
exec {HOLDERR}<&-
这必须输出如下内容:
drwxrwxrwt 4 root root 4096 Jan 01 1970 /tmp
并使用以下内容填充$errmsg
:declare -p errmsg
declare -a errmsg=([0]="ls: cannot access '/tnt': No such file or directory")
再走一步
exec {HOLDERR}<> <(:)
ls -ld /t{mp,nt} 2>&${HOLDERR}
errmsg=()
while read -t 0 -u $HOLDERR;do
read -ru $HOLDERR line
errmsg+=("$line")
done
exec {HOLDERR}<&-
printf "%s\n" "${errmsg[@]}"
完整可用版本
使用trap SIGCHLD
刷新fifo。
printmsg() {
local out=()
out=("${errmsg[@]}")
errmsg=("${errmsg[@]:${#out[@]}}")
[ "${#out[@]}" -gt 0 ] &&
printf "Err: %s\n" "${out[@]}"
}
checkmsg() {
local line
while read -u $HOLDERR -t 0 ;do
read -ru $HOLDERR line &&
errmsg+=("$line")
done
}
msg=()
trap checkmsg CHLD
exec {HOLDERR}<> <(:)
然后
ls -ld /t{mp,nt} 2>&${HOLDERR}
必须输出如下内容:
drwxrwxrwt 4 root root 4096 Jan 01 1970 /tmp
其次:
printmsg
将显示
Err: ls: cannot access '/tnt': No such file or directory
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。