我有一个脚本(片段),正在记录其输出和标准错误:
#!/bin/sh
#...
{
date "+%Y-%m-%d %T"
cd $workdir
ls -ltr validfile badfile #example command that provides stdout, stderr
} | tee -a $logfile
如果我执行上述操作,我会在日志文件中获得标准输出。要在那里也获得标准错误,我可以这样做:
#!/bin/sh
#...
{
date "+%Y-%m-%d %T"
cd $workdir
ls -ltr validfile badfile
} 2>&1 | tee -a $logfile
但是,当从命令行调用脚本中的此版本时,我无法解析错误:
$ ./script.sh 2>/dev/null
将仅显示所有标准输出和标准错误。如果这次我只想将错误置为无效怎么办?
您能向我演示如何将标准错误传送到日志,但在通过命令行或其他脚本调用时将其保留在标准错误上吗?
AIX 7.1,ksh(无 bash)
答案1
使用一些奇特的输出重定向,可以在不使用基本 bash 重定向到进程的情况下实现这一点。
记录标准错误并将其保存在标准错误管道上
#!/bin/sh
exec 4>&1 # important as it "saves" stdout (usually /dev/tty2 for example)
exec 3>&1 # work-in-progress file descriptor
logfile=/var/log/myscript.out
{
{
date "+%Y-%m-%d %T"
cd $workdir
ls -ltr validfile badfile
} 2>&1 1>&3 | tee -a $logfile 1>&2 2>/dev/null 3>&4
} 3>&1 | tee -a $logfile
exec 4>&- # proper form is to clean up when you're done
exec 3>&-
解释:
exec 4>&1
并exec 3>&1
创建新的文件描述符 3 和 4,它们都指向标准输出所指向的内容(很可能是您的终端)。
2>&1
将整个第二级花括号的标准错误重定向到标准输出。1>&3
将标准输出重定向到 fd3 指向的任何内容(这是标准输出,但不在管道 1 中,这很重要!)
| tee -a $logfile
将标准输入(来自第二级花括号,即旧的 stderr)复制到日志文件和标准输出。1>&2
移动标准输出到标准错误(所以回到它所属的位置).2>/dev/null
可能没有必要,但它会重定向来自 tee 的任何错误输出并将其丢弃。3>&4
将管道 3 重定向到管道 4(顺便说一下,它指向 stdout,还记得吗?)。
3>&1
取出第一级括号中的 3 号管道并将其发送到常规标准输出.| tee -a $logfile
捕获标准输入(即括号中的[调整后的]标准输出)并将其复制到日志和标准输出。