要将 standard output 重定向到 Bash 中的截断文件,我知道要使用:
cmd > file.txt
要在 Bash 中重定向标准输出,附加到文件,我知道使用:
cmd >> file.txt
要将标准输出和 standard error 都重定向到截断的文件,我知道要使用:
cmd &> file.txt
如何重定向附加到文件的标准输出和标准错误? cmd &>> file.txt
对我不起作用。
cmd >>file.txt 2>&1
Bash 从左到右执行重定向,如下所示:
>>file.txt:以追加模式打开 file.txt 并将标准输出重定向到那里。 2>&1:将 stderr 重定向到“stdout 当前所在的位置”。在这种情况下,这是一个以附加模式打开的文件。换句话说,&1 重用了 stdout 当前使用的文件描述符。
有两种方法可以做到这一点,具体取决于您的 Bash 版本。
经典且便携(Bash pre-4)的方式是:
cmd >> outfile 2>&1
从 Bash 4 开始的一种不可移植的方式是
cmd &>> outfile
(类似于 &> outfile
)
为了获得良好的编码风格,您应该
确定是否需要考虑可移植性(然后使用经典方式)
决定是否考虑到 Bash pre-4 的可移植性(然后使用经典方式)
无论您使用哪种语法,都不要在同一个脚本中更改它(混淆!)
如果您的脚本已经以 #!/bin/sh
开头(无论是否有意),那么 Bash 4 解决方案以及通常任何特定于 Bash 的代码都不是可行的方法。
还要记住 Bash 4 &>>
只是更短的语法——它没有引入任何新功能或类似的东西。
Bash hackers wiki 中描述了语法(除其他重定向语法外)。
sh
。您可以通过将 SHELL=/bin/bash
添加到 crontab -e
文件来更改默认 shell。
在 Bash 中,您还可以明确指定重定向到不同的文件:
cmd >log.out 2>log_error.out
附加将是:
cmd >>log.out 2>>log_error.out
cmd >log.out 2>&1
之前给出。我正在编辑我的答案以删除第一个示例。
cmd > my.log 2> my.log
不起作用的原因是重定向是从左到右评估的,并且 > my.log
说“创建新文件 my.log
替换现有文件并将 stdout
重定向到该文件”和 之后 i> 已经完成,评估 2> my.log
并显示“创建新文件 my.log
替换现有文件并将 stderr
重定向到该文件”。由于 UNIX 允许删除打开的文件,stdout 现在记录到以前称为 my.log
但已被删除的文件中。一旦该文件的最后一个文件句柄关闭,文件 contents 也将被删除。
cmd > my.log 2>&1
有效,因为 > my.log
说“创建新文件 my.log
替换现有文件并将 stdout
重定向到该文件”,然后已经完成,2>&1
说“点文件句柄2 到文件句柄 1"。并且根据 POSIX 规则,文件句柄 1 始终是标准输出,2 始终是标准错误,因此 stderr
然后从第一次重定向指向已经打开的文件 my.log
。请注意,语法 >&
不会创建或修改实际文件,因此不需要 >>&
。 (如果 first 重定向为 >> my.log
,则文件只是以附加模式打开。)
这应该可以正常工作:
your_command 2>&1 | tee -a file.txt
它将所有日志存储在 file.txt 中,并将它们转储到终端中。
在 Bash 4(以及 Z shell (zsh
) 4.3.11)中:
cmd &>> outfile
开箱即用。
尝试这个:
You_command 1> output.log 2>&1
您对 &> x.file
的使用在 Bash 4 中确实有效。抱歉:(
这里有一些额外的提示。
0, 1, 2, ..., 9 是 bash 中的文件描述符。
0 代表standard input,1 代表standard output,2 代表standard error。 3~9 留作其他临时用途。
任何文件描述符都可以通过使用运算符 >
或 >>
(append) 重定向到其他文件描述符或文件。
用法:
请参阅 Chapter 20. I/O Redirection 中的参考资料。
You_command
的 stderr 重定向到 stdout,将 You_command
的 stdout 重定向到文件 output.log
。此外,它不会附加到文件,但会覆盖它。
1 > output.log 2>&1
另一种方法:
如果使用 &>>
不可用的旧版本 Bash,您还可以执行以下操作:
(cmd 2>&1) >> file.txt
这会生成一个子 shell,因此它的效率低于传统的 cmd >> file.txt 2>&1
方法,因此它不适用于需要修改当前 shell 的命令(例如 cd
、pushd
),但这种方法感觉更对我来说自然且可以理解:
将标准错误重定向到标准输出。通过附加到文件来重定向新的标准输出。
此外,括号消除了任何顺序的歧义,特别是如果您想将标准输出和标准错误传递给另一个命令。
为了避免启动子shell,您可以使用花括号而不是括号来创建组命令:
{ cmd 2>&1; } >> file.txt
(请注意,终止 group 命令需要分号(或换行符)。)
cmd >> file 2>&1
可以在所有 shell 中使用,并且不需要额外的进程来运行。
cmd >> file 2>&1
还是 cmd 2>&1 >> file
,我认为使用 cmd 2>&1 | cat >> file
而不是使用大括号或括号会更容易。对我来说,一旦您了解 cmd >> file 2>&1
的实现实际上是“将 STDOUT 重定向到 file
”,然后是“将 STDERR 重定向到 STDOUT 当前指向的任何文件”(这显然是 {5 } 在第一次重定向之后),很明显您放置重定向的顺序。 UNIX 不支持重定向到流,仅支持流指向的 file 描述符。
来自脚本本身的重定向
您可以从脚本本身计划重定向:
#!/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 上一次运行错误文件
整体.log 附加的整体日志文件
general.err 附加的总体错误文件
combine.log 附加了整体错误和日志组合文件。
仍然输出到终端
对于交互式会话,请使用 stdbuf:
如果您打算在 interactive 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
不定期副业成功案例分享
cmd >>file1 2>>file2
它应该达到你想要的。