在 Bash 中重定向 stderr 和 stdout
我想重定向 标准输出 和 单个文件进程的标准错误。 我如何在 Bash 中做到这一点?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我想重定向 标准输出 和 单个文件进程的标准错误。 我如何在 Bash 中做到这一点?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(15)
请查看此处。 它应该是:
它将标准输出和标准错误重定向到文件filename。
Take a look here. It should be:
It redirects both standard output and standard error to file filename.
这会将标准错误重定向到标准输出,并将标准输出重定向到
some_file
并将其打印到标准输出。This is going to redirect standard error to standard output and standard output to
some_file
and print it to standard output.您可以将 stderr 重定向到 stdout,并将 stdout 重定向到文件中:
注意:重定向的顺序很重要。
以下不等效。
请参阅第 20 章 I/O 重定向
这种格式优于仅适用于 Bash 的最流行的
>
格式。 在 Bourne shell 中,它可以被解释为在后台运行命令。 此外,格式更具可读性 - 2(标准错误)重定向到 1(标准输出)。You can redirect stderr to stdout and the stdout into a file:
NB: The order of redirection is significant.
The following is not equivalent.
See Chapter 20. I/O Redirection
This format is preferred over the most popular
&>
format that only works in Bash. In Bourne shell it could be interpreted as running the command in background. Also the format is more readable - 2 (is standard error) redirected to 1 (standard output).现在,一个简单的 echo 将写入 $LOG_FILE,这对于守护进程很有用。
对于原始帖子的作者,
这取决于您需要实现的目标。 如果您只需要重定向输入/输出从脚本调用的命令,答案已经给出。 我的任务是在当前脚本内重定向,该脚本会影响上述代码片段之后的所有命令/内置命令(包括分支)。
另一个很酷的解决方案是重定向到标准错误和标准输出并立即记录到日志文件,这涉及将“流”分成两部分。 此功能由“tee”命令提供,该命令可以一次写入/附加到多个文件描述符(文件、套接字、管道等):
tee FILE1 FILE2 ... >(cmd1) >(cmd2) ...
所以,从一开始。 假设我们有一个终端连接到 /dev/stdout (文件描述符 #1)和 /dev/stderr (文件描述符 #2)。 实际上,它可以是管道、插座或其他任何东西。
运行具有上述行和另外这一行的脚本的结果
如下:
如果您想看到更清晰的图片,请将这两行添加到脚本中:
Now, a simple echo will write to $LOG_FILE, and it is useful for daemonizing.
To the author of the original post,
It depends what you need to achieve. If you just need to redirect in/out of a command you call from your script, the answers are already given. Mine is about redirecting within current script which affects all commands/built-ins (includes forks) after the mentioned code snippet.
Another cool solution is about redirecting to both standard error and standard output and to log to a log file at once which involves splitting "a stream" into two. This functionality is provided by 'tee' command which can write/append to several file descriptors (files, sockets, pipes, etc.) at once:
tee FILE1 FILE2 ... >(cmd1) >(cmd2) ...
So, from the beginning. Let's assume we have a terminal connected to /dev/stdout (file descriptor #1) and /dev/stderr (file descriptor #2). In practice, it could be a pipe, socket or whatever.
The result of running a script having the above line and additionally this one:
...is as follows:
If you want to see clearer picture, add these two lines to the script:
1>file.log
指示 shell 将标准输出发送到文件file.log
,2>&1
告诉它重定向标准错误(文件描述符 2)到标准输出(文件描述符 1)。注意: 正如 liw.fi 指出的那样,顺序很重要,
2>&1 1>file.log
不起作用。1>file.log
instructs the shell to send standard output to the filefile.log
, and2>&1
tells it to redirect standard error (file descriptor 2) to standard output (file descriptor 1).Note: The order matters as liw.fi pointed out,
2>&1 1>file.log
doesn't work.奇怪的是,这有效:
但这会产生语法错误:
您必须使用:
Curiously, this works:
But this gives a syntax error:
You have to use:
简短回答:
Command >filename 2>&1
或Command &>filename
说明:
考虑以下代码,它将单词“stdout”打印到 stdout 并打印将“stderror”一词改为 stderror。
请注意“&” 运算符告诉 bash 2 是文件描述符(指向 stderr)而不是文件名。 如果我们省略了“&”,此命令会将
stdout
打印到 stdout,并创建一个名为“2”的文件并在其中写入stderror
。通过试验上面的代码,您可以亲自了解重定向运算符的工作原理。 例如,通过更改两个描述符
1,2
中的哪个文件被重定向到/dev/null
,以下两行代码会删除 stdout 中的所有内容,并且分别来自 stderror 的所有内容(打印剩下的内容)。现在,我们可以解释为什么以下代码不产生输出的解决方案:
要真正理解这一点,我强烈建议您阅读此文件描述符表的网页。 假设您已阅读完该内容,我们就可以继续。 请注意,Bash 从左到右处理; 因此 Bash 首先看到
>/dev/null
(与1>/dev/null
相同),并将文件描述符 1 设置为指向 /dev/ null 而不是标准输出。 完成此操作后,Bash 向右移动并看到2>&1
。 这将文件描述符 2 设置为指向与文件描述符 1 相同的文件(而不是文件描述符 1 本身!!!!(请参阅 有关指针的资源 了解更多信息))。 由于文件描述符 1 指向 /dev/null,并且文件描述符 2 指向与文件描述符 1 相同的文件,因此文件描述符 2 现在也指向 /dev/null。 因此,两个文件描述符都指向 /dev/null,这就是不呈现输出的原因。为了测试您是否真正理解这个概念,请尝试猜测我们切换重定向顺序时的输出:
这里的原因是,从左到右计算,Bash 看到 2>&1,因此将文件描述符 2 设置为指向与文件描述符 1 相同的位置,即 stdout。 然后它设置文件描述符 1(记住 >/dev/null = 1>/dev/null)指向 >/dev/null,从而删除通常发送到标准输出的所有内容。 因此,我们剩下的就是没有发送到子 shell 中的 stdout 的内容(括号中的代码),即“stderror”。
值得注意的是,尽管 1 只是指向 stdout 的指针,但通过
2>&1
将指针 2 重定向到 1 并不会形成指针链 2 -> 。 1-> 标准输出。 如果是这样,由于将 1 重定向到 /dev/null,代码2>&1 >/dev/null
将给出指针链 2 -> 。 1-> /dev/null,因此代码不会生成任何内容,与我们上面看到的相反。最后,我要指出的是,有一种更简单的方法可以做到这一点:
来自第 3.6.4 节 这里,我们看到我们可以使用运算符
&>
来重定向stdout和stderr。 因此,要将任何命令的 stderr 和 stdout 输出重定向到\dev\null
(这会删除输出),我们只需键入$ 命令 &> /dev/null
或者在我的示例中:
关键要点:
2>&1 >/dev/null
是 !=>/dev/null 2>&1
。 一个产生输出,另一个不产生输出!最后看看这些很棒的资源:
有关重定向的 Bash 文档 , 文件描述符表说明, 指针简介
Short answer:
Command >filename 2>&1
orCommand &>filename
Explanation:
Consider the following code which prints the word "stdout" to stdout and the word "stderror" to stderror.
Note that the '&' operator tells bash that 2 is a file descriptor (which points to the stderr) and not a file name. If we left out the '&', this command would print
stdout
to stdout, and create a file named "2" and writestderror
there.By experimenting with the code above, you can see for yourself exactly how redirection operators work. For instance, by changing which file which of the two descriptors
1,2
, is redirected to/dev/null
the following two lines of code delete everything from the stdout, and everything from stderror respectively (printing what remains).Now, we can explain why the solution why the following code produces no output:
To truly understand this, I highly recommend you read this webpage on file descriptor tables. Assuming you have done that reading, we can proceed. Note that Bash processes left to right; thus Bash sees
>/dev/null
first (which is the same as1>/dev/null
), and sets the file descriptor 1 to point to /dev/null instead of the stdout. Having done this, Bash then moves rightwards and sees2>&1
. This sets the file descriptor 2 to point to the same file as file descriptor 1 (and not to file descriptor 1 itself!!!! (see this resource on pointers for more info)) . Since file descriptor 1 points to /dev/null, and file descriptor 2 points to the same file as file descriptor 1, file descriptor 2 now also points to /dev/null. Thus both file descriptors point to /dev/null, and this is why no output is rendered.To test if you really understand the concept, try to guess the output when we switch the redirection order:
The reasoning here is that evaluating from left to right, Bash sees 2>&1, and thus sets the file descriptor 2 to point to the same place as file descriptor 1, ie stdout. It then sets file descriptor 1 (remember that >/dev/null = 1>/dev/null) to point to >/dev/null, thus deleting everything which would usually be send to to the standard out. Thus all we are left with was that which was not send to stdout in the subshell (the code in the parentheses)- i.e. "stderror".
The interesting thing to note there is that even though 1 is just a pointer to the stdout, redirecting pointer 2 to 1 via
2>&1
does NOT form a chain of pointers 2 -> 1 -> stdout. If it did, as a result of redirecting 1 to /dev/null, the code2>&1 >/dev/null
would give the pointer chain 2 -> 1 -> /dev/null, and thus the code would generate nothing, in contrast to what we saw above.Finally, I'd note that there is a simpler way to do this:
From section 3.6.4 here, we see that we can use the operator
&>
to redirect both stdout and stderr. Thus, to redirect both the stderr and stdout output of any command to\dev\null
(which deletes the output), we simply type$ command &> /dev/null
or in case of my example:
Key takeaways:
2>&1 >/dev/null
is !=>/dev/null 2>&1
. One generates output and the other does not!Finally have a look at these great resources:
Bash Documentation on Redirection, An Explanation of File Descriptor Tables, Introduction to Pointers
它是相关的:将标准输出和标准错误写入 syslog。
它几乎可以工作,但不是来自 xinetd ;(
It is related: Writing standard output and standard error to syslog.
It almost works, but not from xinetd ;(
对于需要“管道”的情况,可以使用
|&
。例如:
或者
这些基于 Bash 的解决方案可以分别通过管道传输标准输出和标准错误(从“sort -c”的标准错误,或从标准错误到“sort -h”)。
For the situation when "piping" is necessary, you can use
|&
.For example:
or
These Bash-based solutions can pipe standard output and standard error separately (from standard error of "sort -c", or from standard error to "sort -h").
我想要一个解决方案,将 stdout 和 stderr 的输出写入日志文件,并且 stderr 仍在控制台上。 所以我需要通过 tee 复制 stderr 输出。
这是我找到的解决方案:
I wanted a solution to have the output from stdout plus stderr written into a log file and stderr still on console. So I needed to duplicate the stderr output via tee.
This is the solution I found:
添加到 Fernando Fabreti 所做的,我稍微改变了功能并删除了
&-
关闭,它对我有用。Adding to what Fernando Fabreti did, I changed the functions slightly and removed the
&-
closing and it worked for me.“最简单”的方法(仅限 Bash 4):
The "easiest" way (Bash 4 only):
当您考虑使用诸如
exec 2>&1
之类的东西时,我发现如果可能的话,使用 Bash 函数重写代码会更容易阅读,如下所示:In situations when you consider using things like
exec 2>&1
, I find it easier to read, if possible, rewriting code using Bash functions like this:以下函数可用于自动切换 stdout/stderr 和日志文件之间的输出过程。
脚本内的使用示例:
The following functions can be used to automate the process of toggling outputs beetwen stdout/stderr and a logfile.
Example of usage inside script:
对于 tcsh,我必须使用以下命令:
如果使用
command &> ; file
,它将给出“无效的空命令”错误。For tcsh, I have to use the following command:
If using
command &> file
, it will give an "Invalid null command" error.