Bash-将所有输出发送到日志文件,但显示错误

Bash-将所有输出发送到日志文件,但显示错误,bash,shell,unix,file-descriptor,io-redirection,Bash,Shell,Unix,File Descriptor,Io Redirection,在bash脚本中,除了我使用echo专门输出的输出之外,是否可以将所有输出转到日志文件,但是如果输出中有错误,它应该显示在终端中(当然还有日志文件)?UNIX终端通常提供两个输出文件描述符,stdout和stderr,默认情况下,这两者都将转到终端 性能良好的程序将其“标准”输出发送到stdout,将错误发送到stderr。例如,echo写入标准输出grep将匹配行写入stdout,但如果出现错误,例如无法读取文件,则错误将转到stderr 您可以使用(对于stdout)和2>(对于stderr

在bash脚本中,除了我使用echo专门输出的输出之外,是否可以将所有输出转到日志文件,但是如果输出中有错误,它应该显示在终端中(当然还有日志文件)?

UNIX终端通常提供两个输出文件描述符,
stdout
stderr
,默认情况下,这两者都将转到终端

性能良好的程序将其“标准”输出发送到
stdout
,将错误发送到
stderr
。例如,
echo
写入标准输出
grep
将匹配行写入
stdout
,但如果出现错误,例如无法读取文件,则错误将转到
stderr

您可以使用
(对于
stdout
)和
2>
(对于
stderr
)重定向这些文件。因此:

将输出写入
日志
,将错误写入
错误

因此,您的部分需求可以通过以下方式得到满足:

 command >log
。。。错误将继续通过标准输出发送到终端

您的额外要求是“除了我专门用echo输出的输出”

您的
echo
s转到stderr可能就足够了:

 echo "Processing next part" >&2
&2
stdout
从该命令重定向到
stderr
。这是在shell脚本中输出错误(有时是信息输出)的标准方法

如果您需要的不止这些,那么您可能需要使用更多的文件描述符来执行更复杂的操作。尝试:


表现良好的UNIX程序往往避免使用额外的文件描述符执行复杂的操作。约定是将自己限制为
stdout
stderr
,任何进一步的输出都在命令行参数中指定为文件名。

以下是使用附加文件描述符可以执行的操作:

#!/bin/bash

# open fd=3 redirecting to 1 (stdout)
exec 3>&1

# redirect stdout/stderr to a file but show stderr on terminal
exec >file.log 2> >(tee >(cat >&3))

# function echo to show echo output on terminal
echo() {
   # call actual echo command and redirect output to fd=3
   command echo "$@" >&3
}

# script starts here
echo "show me"
printf "=====================\n"
printf "%s\n" "hide me"
ls foo-foo
date
tty
echo "end of run"

# close fd=3
exec 3>&-
运行脚本后,它将在终端上显示以下内容:

show me
ls: cannot access 'foo-foo': No such file or directory
end of run
如果执行
cat file.log
,则会显示:

=====================
hide me
ls: cannot access 'foo-foo': No such file or directory
Fri Dec  2 14:20:47 EST 2016
/dev/ttys002
  • 在终端上,我们只得到
    echo
    命令和所有错误的输出
  • 在日志文件中,我们从脚本中获得错误和剩余输出

您能否确认需要这3种输出?1) 您的echo应仅出现在控制台上,2)其他标准输出应仅出现在日志文件中,3)错误输出应同时出现在控制台和日志文件中。是的,完全正确。您是否希望仅将
echo
的输出显示在标准输出上?那printf呢??我只在脚本中使用“echo”向用户显示状态。一个小小的吹毛求疵。。。并不是UNIX终端提供stdin、stdout和stderr。即使不是在终端中运行的进程在启动时也有这三个文件描述符(重要的区别是,许多守护进程首先关闭这三个文件描述符)。这实际上只是UNIX进程模型的一个特性。。。我想你甚至可以称之为API的一部分。。。
=====================
hide me
ls: cannot access 'foo-foo': No such file or directory
Fri Dec  2 14:20:47 EST 2016
/dev/ttys002