Avi*_*Avi 53 bash io-redirection
我有一个 bash 文件,我需要将所有输出重定向到一个文件、调试日志以及终端。我需要将 stdout 和 stderr 都重定向到调试并记录脚本中的所有命令。
我不想为2>&1 | tee -a $DEBUG文件中的每个命令添加。我可以忍受| tee -a $DEBUG。
我记得有一种方法可以用类似exec 2>&1.
目前我正在使用以下内容:
#!/bin/bash
DEBUGLOG=/tmp/debug
exec 2>&1
somecommand | tee -a $DEBUGLOG
somecommand2 | tee -a $DEBUGLOG
somecommand3 | tee -a $DEBUGLOG
Run Code Online (Sandbox Code Playgroud)
但它不起作用。有没有人有解决方案/可以解释原因?
slm*_*slm 50
您可以在脚本的顶部像这样使用 exec:
exec > >(tee "$HOME/somefile.log") 2>&1
Run Code Online (Sandbox Code Playgroud)
例如:
#!/bin/bash -
exec > >(tee "$HOME/somefile.log") 2>&1
echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2
Run Code Online (Sandbox Code Playgroud)
给我输出到文件 $HOME/somefile.log和终端,如下所示:
/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye
Run Code Online (Sandbox Code Playgroud)
Bat*_*hyX 46
至于一次重定向大量命令的解决方案:
#!/bin/bash
{
somecommand
somecommand2
somecommand3
} 2>&1 | tee -a $DEBUGLOG
Run Code Online (Sandbox Code Playgroud)
为什么您的原始解决方案不起作用: exec 2>&1 会将标准错误输出重定向到您的 shell 的标准输出,如果您从控制台运行脚本,它将成为您的控制台。命令的管道重定向只会重定向命令的标准输出。
从 的角度来看somecommand,它的标准输出进入连接到的管道tee,标准错误进入与 shell 的标准错误相同的文件/伪文件,你重定向到 shell 的标准输出,这将是如果您从控制台运行程序,则控制台。
解释它的一种真正方法是看看真正发生了什么:
如果从终端运行 shell,它的原始环境可能如下所示:
stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42
Run Code Online (Sandbox Code Playgroud)
在您将标准错误重定向到标准输出 ( exec 2>&1) 之后,您……基本上什么都没有改变。但是如果你将脚本的标准输出重定向到一个文件,你最终会得到这样的环境:
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42
Run Code Online (Sandbox Code Playgroud)
然后将 shell 标准错误重定向到标准输出最终会像这样:
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file
Run Code Online (Sandbox Code Playgroud)
运行一个命令会继承这个环境。如果您运行一个命令并将其通过管道传输到 tee,则该命令的环境将是:
stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file
Run Code Online (Sandbox Code Playgroud)
因此,您的命令的标准错误仍然属于 shell 用作其标准错误的内容。
实际上,您可以通过查看/proc/[pid]/fd:usels -l来查看命令的环境,还可以列出符号链接的内容。这0这里文件是标准输入、1标准输出和2标准错误。如果该命令打开更多文件(大多数程序都这样做),您也会看到它们。程序还可以选择重定向或关闭其标准输入/输出并重用0,1和2.