我在下面的两个shell脚本中尝试了以下(简化的(代码。
该脚本调用一个R脚本,其中运行的代码将根据发生的情况生成标准输出和错误流。
我试图实现的是像往常一样在控制台上显示输出和错误流,但当脚本运行失败时(例如,RScript产生错误流(,我想将R生成的错误消息保存在sqlite数据库中,但当它退出时,控制台上仍然显示正常的输出和错误。我已经尝试了多种形式的Rscript函数的重定向输出,但我要么最终不将任何内容保存到数据库(除了行号(,要么我可以保存错误消息,但控制台上不会显示任何内容。。。
这不会将错误消息保存到DB(行号会(,但所有内容都将在控制台上
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
这将把错误消息保存到DB中,但控制台上再也没有了
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)
我到处寻找一种方法,只捕获变量的错误流,并在控制台上保持输出不变(输出和错误(,但我被卡住了。
试试这个
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(警告,这将起作用,因为操作系统进行缓冲,所以只有当输出保持在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
并用类似于declare -p errmsg
的东西弹出$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 "%sn" "${errmsg[@]}"
完全可用版本
用trap SIGCHLD
冲洗fifo。
printmsg() {
local out=()
out=("${errmsg[@]}")
errmsg=("${errmsg[@]:${#out[@]}}")
[ "${#out[@]}" -gt 0 ] &&
printf "Err: %sn" "${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