1768

要将标准输出重定向到 Bash 中的截断文件,我知道要使用:

cmd > file.txt

要在 Bash 中重定向标准输出,附加到文件,我知道使用:

cmd >> file.txt

要将标准输出和标准错误都重定向到截断的文件,我知道要使用:

cmd &> file.txt

如何重定向附加到文件的标准输出和标准错误?cmd &>> file.txt对我不起作用。

4

8 回答 8

2286
cmd >>file.txt 2>&1

Bash 从左到右执行重定向,如下所示:

  1. >>file.txt:以附加模式打开file.txt并重定向stdout到那里。
  2. 2>&1:重定向stderrstdout当前要去的地方”。在这种情况下,这是一个以附加模式打开的文件。换句话说,&1重用当前使用的文件描述符stdout
于 2009-05-18T04:23:16.287 回答
407

有两种方法可以做到这一点,具体取决于您的 Bash 版本。

经典且可移植的(Bash pre-4)方式是:

cmd >> outfile 2>&1

从Bash 4开始的一种不可移植的方式是

cmd &>> outfile

(类似于&> outfile

为了获得良好的编码风格,您应该

  • 确定是否需要考虑可移植性(然后使用经典方式)
  • 决定是否考虑到 Bash pre-4 的可移植性(然后使用经典方式)
  • 无论您使用哪种语法,都不要在同一个脚本中更改它(混淆!)

如果您的脚本已经开始#!/bin/sh(无论是否有意),那么 Bash 4 解决方案以及通常任何特定于 Bash 的代码都不是要走的路。

还要记住,Bash 4&>>只是更短的语法——它没有引入任何新功能或类似的东西。

语法(除了其他重定向语法)在Bash 黑客 wiki中描述。

于 2009-05-18T04:42:13.683 回答
102

在 Bash 中,您还可以明确指定重定向到不同的文件:

cmd >log.out 2>log_error.out

附加将是:

cmd >>log.out 2>>log_error.out
于 2013-07-24T18:09:45.047 回答
74

这应该可以正常工作:

your_command 2>&1 | tee -a file.txt

它将所有日志存储在file.txt中,并将它们转储到终端中。

于 2015-12-12T06:17:38.270 回答
69

在 Bash 4(以及Z shell ( zsh) 4.3.11)中:

cmd &>> outfile

开箱即用。

于 2012-03-27T18:24:48.073 回答
27

试试这个:

You_command 1> output.log  2>&1

&> x.file在 Bash 4 中的使用确实有效。对此感到抱歉:(

这里有一些额外的提示。

0, 1, 2, ..., 9 是 bash 中的文件描述符。

0代表标准输入,1代表标准输出,2代表标准错误。3~9 留作其他临时用途。

任何文件描述符都可以通过使用运算符>>>(附加)重定向到其他文件描述符或文件。

用法:< file_descriptor > > <文件名| &file_descriptor >

请参阅第 20 章中的参考资料。I/O 重定向

于 2014-04-10T05:56:00.840 回答
15

另一种方法:

如果在&>>不可用的情况下使用旧版本的 Bash,您还可以执行以下操作:

(cmd 2>&1) >> file.txt

这会产生一个子shell,因此它的效率低于传统方法 的cmd >> file.txt 2>&1,因此它不适用于需要修改当前 shell 的命令(例如cd, pushd),但这种方法对我来说感觉更自然和易于理解:

  1. 将标准错误重定向到标准输出。
  2. 通过附加到文件来重定向新的标准输出。

此外,括号消除了任何顺序的歧义,特别是如果您想将标准输出和标准错误传递给另一个命令。

为了避免启动子shell,您可以使用花括号而不是括号来创建组命令

{ cmd 2>&1; } >> file.txt

(请注意,终止 group 命令需要分号(或换行符)。)

于 2019-02-15T16:11:31.437 回答
8

来自脚本本身的重定向

您可以从脚本本身计划重定向:

#!/bin/bash

exec 1>>logfile.txt
exec 2>&1

/bin/ls -ld /tmp /tnt

运行它会创建/追加logfile.txt,包含:

/bin/ls: cannot access '/tnt': No such file or directory
drwxrwxrwt 2 root root 4096 Apr  5 11:20 /tmp

登录到许多不同的文件

您可以创建两个不同的日志文件,附加到一个整体日志并重新创建另一个最后一个日志:

#!/bin/bash

if [ -e last.log ] ;then
    mv -f last.log last.old
fi
exec 1> >(tee -a overall.log /dev/tty >last.log)
exec 2>&1

ls -ld /tnt /tmp

运行此脚本将

  • 如果last.log已经存在,将它们重命名为(如果存在则last.old覆盖)。last.old
  • 创建一个新的last.log.
  • 将所有内容附加到overall.log
  • 将所有内容输出到终端。

简单组合的日志

#!/bin/bash

[ -e last.err ] && mv -f last.err lasterr.old
[ -e last.log ] && mv -f last.log lastlog.old

exec 2> >(tee -a overall.err combined.log /dev/tty >last.err)
exec 1> >(tee -a overall.log combined.log /dev/tty >last.log)

ls -ld /tnt /tmp

所以你有了

  • last.log上次运行日志文件
  • last.err上次运行错误文件
  • lastlog.old以前的运行日志文件
  • lasterr.old上一次运行错误文件
  • overall.log附加的整体日志文件
  • overall.err附加的整体错误文件
  • combined.log附加了整体错误和日志组合文件。
  • 仍然输出到终端

对于交互式会话,请使用stdbuf

如果你打算在交互式shell 中使用它,你必须告诉tee不要缓冲他的输入/输出:

# Source this to multi-log your session
[ -e last.err ] && mv -f last.err lasterr.old
[ -e last.log ] && mv -f last.log lastlog.old
exec 2> >(exec stdbuf -i0 -o0 tee -a overall.err combined.log /dev/tty >last.err)
exec 1> >(exec stdbuf -i0 -o0 tee -a overall.log combined.log /dev/tty >last.log)

一旦采购了这个,你可以尝试:

ls -ld /tnt /tmp
于 2021-04-05T09:40:19.683 回答