如何使用 Bash 将标准输出和标准错误重定向并附加到文件
要将 标准输出 重定向到 Bash 中的截断文件,我知道使用:
cmd > file.txt
要在 Bash 中重定向标准输出,附加到文件,我知道要使用:
cmd >> file.txt
重定向标准输出和 标准错误到截断的文件,我知道使用:
cmd &> file.txt
如何将标准输出和附加到文件的标准错误重定向? cmd &>> file.txt
对我不起作用。
To redirect standard output to a truncated file in Bash, I know to use:
cmd > file.txt
To redirect standard output in Bash, appending to a file, I know to use:
cmd >> file.txt
To redirect both standard output and standard error to a truncated file, I know to use:
cmd &> file.txt
How do I redirect both standard output and standard error appending to a file? cmd &>> file.txt
did not work for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
Bash 从左到右执行重定向,如下所示:
>>file.txt
:以追加模式打开file.txt
并重定向stdout
那里。2>&1
:将stderr
重定向到“stdout
当前所在位置”。 在本例中,这是一个以附加模式打开的文件。 换句话说,&1
重用了stdout
当前使用的文件描述符。Bash executes the redirects from left to right as follows:
>>file.txt
: Openfile.txt
in append mode and redirectstdout
there.2>&1
: Redirectstderr
to "wherestdout
is currently going". In this case, that is a file opened in append mode. In other words, the&1
reuses the file descriptor whichstdout
currently uses.有两种方法可以执行此操作,具体取决于您的 Bash 版本。
经典且可移植的 (Bash pre-4) 方式是:
非可移植方式,从 Bash 4 开始是
(类似于
&> outfile
)对于良好的编码风格,您应该
如果您的脚本已经以
#!/bin/sh
开头(无论是否有意),那么 Bash 4 解决方案,以及一般的任何 Bash - 特定的代码,不是要走的路。另请记住,Bash 4
&>>
只是更短的语法 - 它不会引入任何新功能或类似的内容。该语法(除了其他重定向语法)在 Bash hackers wiki 中进行了描述。
There are two ways to do this, depending on your Bash version.
The classic and portable (Bash pre-4) way is:
A nonportable way, starting with Bash 4 is
(analog to
&> outfile
)For good coding style, you should
If your script already starts with
#!/bin/sh
(no matter if intended or not), then the Bash 4 solution, and in general any Bash-specific code, is not the way to go.Also remember that Bash 4
&>>
is just shorter syntax — it does not introduce any new functionality or anything like that.The syntax is (beside other redirection syntax) described in the Bash hackers wiki.
在 Bash 中,您还可以显式指定对不同文件的重定向:
追加将是:
In Bash you can also explicitly specify your redirects to different files:
Appending would be:
这应该可以正常工作:
它将所有日志存储在 file.txt 中,并将它们转储到终端中。
This should work fine:
It will store all logs in file.txt as well as dump them in the terminal.
在 Bash 4 中(以及 Z shell (
zsh
) 4.3。 11):刚开箱。
In Bash 4 (as well as Z shell (
zsh
) 4.3.11):just out of box.
试试这个:
您对
> 的用法 x.file
在 Bash 4 中可以工作。抱歉:(这里有一些额外的提示。0
, 1, 2, ..., 9 是 bash 中的文件描述符。0
代表 标准输入,1代表标准输出,2代表标准错误。3~9可供任何其他临时使用。
任何文件描述符都可以使用运算符
>
或重定向到其他文件描述符或文件。 >>>(附加)
。
<file_descriptor> > <文件名 | &file_descriptor>
请参阅第 20 章 I/O 重定向。
Try this:
Your usage of
&> x.file
does work in Bash 4. Sorry for that: (Here comes some additional tips.
0, 1, 2, ..., 9 are file descriptors in bash.
0 stands for standard input, 1 stands for standard output, 2 stands for standard error. 3~9 is spare for any other temporary usage.
Any file descriptor can be redirected to other file descriptor or file by using operator
>
or>>
(append).Usage:
<file_descriptor> > <filename | &file_descriptor>
Please see the reference in Chapter 20. I/O Redirection.
一些评论和有用的技巧
简介
来自What does " 2>&1 "mean?,我将在这个答案中使用命令:
用于同时填充
STDIN
和STDERR
。 (希望您的根中没有任何条目,称为tnt
。)来自脚本本身的重定向
您可以计划从脚本本身:
运行此命令将创建/附加
logfile.txt
,其中包含:或者
在创建或附加标准输出到
logfile.txt
时并创建或将错误输出附加到errfile.txt
。记录到许多不同的文件
您可以创建两个不同的日志文件,附加到一个总体日志并重新创建另一个最后日志:
运行此脚本将
lastlog.txt 已存在,请将其重命名为
lastlog.old
(如果存在,则覆盖lastlog.old
)。lastlog.txt
。overall.log
简单和组合日志
因此您有
lastlog.txt
上次运行日志文件lasterr.txt
上次运行错误文件lastlog.old 上一次运行日志文件
lasterr.old
上一次运行错误文件overall.log
附加总体日志文件overall.err
附加总体错误文件combined.log
附加总体错误和日志组合文件。相同,使用时间戳日志文件名:
$sTime
以确保两个文件将呈现完全相同的相同时间戳。 (如果$EPOCHSECONDS
被调用两次,它们在每次扩展之间可能会有所不同!)$$
以保证唯一性。第三次运行后,您必须找到 9 个文件:
对于交互式会话,请使用stdbuf
:关于Fonic' comment 经过一些测试,我必须同意:使用
tee
,stdbuf
是没用的。但是......If you plan to use this in *interactive* shell, you must tell `tee` to not buffering his input/output:
一旦来源这个,你可以尝试:
更复杂的示例
来自我的关于如何将Unix时间戳转换为日期字符串的3条评论
我使用了更复杂的命令来实时解析和重组
squid
的日志:每行都以 UNIX EPOCH 开头em> 以毫秒为单位,我在第一个点上分割线,在 EPOCH SECONDS 之前添加@
符号将它们传递给
date -f - +%F\ %T
然后使用paste -d 重新组合
。date
的输出以及带有点的行的其余部分。对于
date
,需要stdbuf
...关于
exec
和stdbuf
命令的一些解释:运行<使用
$(...)
或<(...)
进行 code>forks 是通过运行 subshell 来完成的将在另一个子shell(subsubshell)中执行二进制文件。exec
命令告诉 shell 脚本中没有更多命令要运行,因此将执行 binary (stdbuf ... tee
)作为替换进程,处于同一级别(无需预留更多内存来运行另一个子进程)。来自
bash
的手册页(man -P'less +/^\ *exec\ ' bash
):<块引用>
这并不是真正需要的,但可以减少系统占用空间。
来自
stdbuf
的手册页:<块引用>
<前><代码>名称
stdbuf - 运行命令,并修改缓冲
其标准流的操作。
这将告诉系统为
tee
命令使用无缓冲 I/O。 因此,当某些输入到来时,所有输出都将立即更新。Some remarks and useful tricks
Introduction
From What does " 2>&1 " mean?, I will use in this answer the command:
for populating simultaneously both
STDIN
andSTDERR
. (In the hope you don't have any entry in your root, calledtnt
.)Redirections from script himself
You could plan redirections from the script itself:
Running this will create/append
logfile.txt
, containing:Or
While create or append standard output to
logfile.txt
and create or append errors output toerrfile.txt
.Log to many different files
You could create two different logfiles, appending to one overall log and recreating another last log:
Running this script will
lastlog.txt
already exist, rename them tolastlog.old
(overwritinglastlog.old
if they exist).lastlog.txt
.overall.log
Simple and combined logs
So you have
lastlog.txt
last run log filelasterr.txt
last run error filelastlog.old
previous run log filelasterr.old
previous run error fileoverall.log
appended overall log fileoverall.err
appended overall error filecombined.log
appended overall error and log combined file.Same, using timestamped log filenames:
$sTime
in order to ensure both file will present exactly same timestamp. (If$EPOCHSECONDS
is invoked two times, they could differ between each expansion!)$$
in order to ensure unicity.after 3rd run, you must found 9 files:
And for interactive session, usestdbuf
:Regarding Fonic' comment and after some test, I have to agree: with
tee
,stdbuf
is useless. But ...If you plan to use this in *interactive* shell, you must tell `tee` to not buffering his input/output:
Once sourced this, you could try:
More complex sample
From my 3 remarks about how to Convert Unix timestamp to a date string
I've used more complex command to parse and reassemble
squid
's log in real time: As each line begin by an UNIX EPOCH with milliseconds, I split the line on 1st dot, add@
symbol before EPOCH SECONDS topass them to
date -f - +%F\ %T
then reassembledate
's output and the rest of line with a dot by usingpaste -d .
.With
date
,stdbuf
was required...Some explanations about
exec
andstdbuf
commands:Running
forks
by using$(...)
or<(...)
is done by running subshell wich will execute binaries in another subshell (subsubshell). Theexec
command tell shell that there are not further command in script to be run, so binary (stdbuf ... tee
) will be executed as replacement process, at same level (no need to reserve more memory for running another sub-process).From
bash
's man page (man -P'less +/^\ *exec\ ' bash
):This is not really needed, but reduce system footprint.
From
stdbuf
's man page:This will tell system to use unbuffered I/O for
tee
command. So all outputs will be updated immediately, when some input are coming.另一种方法:
如果使用旧版本的 Bash,其中
&>>
不可用,您还可以这样做:这会生成一个子 shell,因此它的效率低于
的传统方法cmd>> file.txt 2>&1
,因此它不适用于需要修改当前 shell 的命令(例如cd
、pushd
),但这种方法对我来说更自然、更容易理解:此外,括号消除了顺序的任何歧义,特别是如果您想将标准输出和标准错误通过管道传输到另一个命令。
为了避免启动子 shell,您可以使用大括号而不是括号来创建组命令:(
请注意,需要分号(或换行符)来终止组命令。)
Another approach:
If using older versions of Bash where
&>>
isn't available, you also can do:This spawns a subshell, so it's less efficient than the traditional approach of
cmd >> file.txt 2>&1
, and it consequently won't work for commands that need to modify the current shell (e.g.cd
,pushd
), but this approach feels more natural and understandable to me:Also, the parentheses remove any ambiguity of order, especially if you want to pipe standard output and standard error to another command instead.
To avoid starting a subshell, you instead could use curly braces instead of parentheses to create a group command:
(Note that a semicolon (or newline) is required to terminate the group command.)
这真是太好了!
将输出重定向到当前脚本内的日志文件和标准输出。
参考https://stackoverflow.com/a/314678/5449346,非常简单干净,它重定向了所有脚本的输出到日志文件和stdout,包括脚本中调用的脚本:
This is terribly good!
Redirect the output to log file and stdout within the current script.
Refer to https://stackoverflow.com/a/314678/5449346, very simple and clean, it redirects all the script's output to the log file and stdout, including the scripts called in the script: