重定向和记录脚本输出

重定向和记录脚本输出

我正在尝试整理以下片段,设计目标是记录脚本的所有输出,而不应该是包装器。线条越少越好。

我不关心用户输入(在这个阶段),目标脚本以非交互方式运行。

该片段需要

  • 输出 stdout 到日志,并始终回显到控制台
  • 输出 stderr 到日志,并回显到控制台 iff 调试已启用
  • stderr 消息应该带有时间戳和其他有用的前缀

目前我有以下内容,仅在最新版本的 bash(4.2+?)下进行测试,例如在 Ubuntu 中精确,但在 CentOS6 上表现不佳。

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
  && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
  || exec 2>> ${DEBUG_LOG}

那么这个...

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
  echo -e "$(date +%T) ${0##*/}: $1" \
    | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
  if [ "${DEBUG_TEST}" = "true" ]; then 
    msg_log "$1"
  else
    echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
  fi
}

我可以echo调用这些 msg 过程之一,例如msg_con "hello world".
此外,脚本输出将通过在调用时设置为环境变量(例如 DEBUG_TEST=true myscript.

我读到 exec 可能无法在某些 shell(例如 busybox)中工作。有一个 mkfifo 和 fork 组合https://stackoverflow.com/a/5200754做了类似的事情,但除非绝对需要,否则我宁愿不使用 fork。

请更喜欢 bash 示例,但是在 sh 下工作或更便携的东西会更好。有任何想法吗?

答案1

function startLogging {
    exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
    [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
    echo "=== Log started for $$ at $(date +%F-%T) ==="
}

您需要将 $logfile 设置为某些内容

答案2

exec > filename应该在 sh 中工作,并且它实际上在 busybox v1.15.3(2011 年 11 月)中工作。但进程替换>(command)是不可移植的,因为它是 bash 扩展。只是避免在脚本中使用它。为什么>>对你来说还不够?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

另一个解决方案是在脚本之外指定重定向。当您的脚本在后台调用时(通过 cron 或系统脚本等),应该像这样调用它们

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

当您手动调用脚本并且想要查看输出时,只需调用它而无需重定向。

答案3

这两个例子将实现您所说的目标

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

或者

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1

答案4

您可以使用tee命令或script命令,两者都非常有用。

相关内容