如何将 stderr 重定向到文件

如何将 stderr 重定向到文件

当使用 nohup 将命令在后台运行时,一些内容会出现在终端中。

cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

我想将该内容保存到文件中。

答案1

Linux(和其他操作系统)中有两个主要的输出流:标准输出 (stdout) 和标准错误 (stderr)。错误消息(如您​​显示的消息)将打印到标准错误。经典的重定向运算符 ( command > file) 仅重定向标准输出,因此标准错误仍显示在终端上。要重定向 stderr,您有几种选择:

  1. 将 stdout 重定向到一个文件,将 stderr 重定向到另一个文件:

    command > out 2>error
    
  2. 将 stdout 重定向到文件 ( >out),然后将 stderr 重定向到 stdout ( 2>&1):

    command >out 2>&1
    
  3. 将两者都重定向到一个文件(并非所有 shell 都支持此功能,例如bashzsh支持它,但是shksh不支持):

    command &> out
    

有关各种控制和重定向运算符的更多信息,请参阅这里

答案2

首先要注意的是,根据你的目的和 shell,有几种方法,因此这需要对多个方面有一点了解。此外,某些命令(例如time和)strace默认将输出写入 stderr,并且可能提供或不提供特定于该命令的重定向方法

重定向背后的基本原理是,shell 生成的进程(假设它是外部命令而不是 shell 内置命令)是通过fork()execve()系统调用创建的,在此之前,另一个系统调用在发生dup2()之前执行必要的重定向execve()。从这个意义上讲,重定向是从父 shell 继承的。m&>nm>n.txt通知 shell 如何执行open()dup2()系统调用(另请参阅输入重定向的工作原理重定向和管道有什么区别, 和输出重定向中的 & 到底是什么意思

Shell 重定向

最典型的是2>通过伯恩式贝壳, 例如dash(符号链接到/bin/sh)和bash;第一个是默认的、符合 POSIX 标准的 shell,另一个是大多数用户用于交互式会话的 shell。它们的语法和功能不同,但幸运的是,错误流重定向的工作原理相同(非标准&>重定向除外)。对于 csh 及其衍生产品,stderr 重定向在那里不太起作用。

让我们回到2>第部分。需要注意两个关键点:>表示重定向运算符,我们在这里打开一个文件,2整数代表 stderr 文件描述符;实际上,这正是 POSIX shell 语言标准中对重定向的定义第2.7节

[n]redir-op word

对于简单>重定向,1整数隐含在 中stdout,即echo Hello World > /dev/null与 相同echo Hello World 1>/dev/null。请注意,整数或重定向运算符不能用引号引起来,否则 shell 不会将它们识别为整数或重定向运算符,而是将其视为文本字符串。至于间距,整数必须紧挨着重定向运算符,但文件可以紧挨着重定向运算符,也可以不紧挨着,即command 2>/dev/nullcommand 2> /dev/null都可以正常工作。

shell 中典型命令的简化语法如下

 command [arg1] [arg2]  2> /dev/null

这里的诀窍是重定向可以出现在任何地方。也就是说2> command [arg1]command 2> [arg1]都是有效的。请注意,对于bashshell,存在&>同时重定向 stdout 和 stderr 流的方法,但同样 - 这是 bash 特有的,如果您追求脚本的可移植性,它可能不起作用。另请参阅Ubuntu 维基&> 和 2>&1 有什么区别

笔记:重定向>运算符截断如果文件存在,则将其覆盖。 可2>>用于附加stderr到文件。

您可能注意到,>它只用于一个命令。对于脚本,我们可以从外部重定向整个脚本的 stderr 流,myscript.sh 2> /dev/null或者我们可以使用exec 内置. 可以说,exec 内置函数能够重新连接整个 shell 会话的流,无论是通过交互方式还是通过脚本。例如

#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file

在此示例中,日志文件应显示stat: cannot stat '/etc/non_existing_file': No such file or directory

另一种方法是通过函数。科普丘塞克在他的回答中指出,我们可以编写已附加重定向的函数声明,即

some_function(){
    command1
    command2
} 2> my_log_file.txt

仅向 stderr 写入的命令

time和等命令strace默认将其输出写入 stderr。对于time命令,唯一可行的替代方案是重定向整个命令的输出,即

time echo foo 2>&1 > file.txt

或者,如果你想分离输出,可以重定向同步列表或子 shell(如相关帖子):

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

其他命令,例如stracedialog提供重定向 stderr 的方法。strace具有-o <filename.txt>允许指定应将输出写入的文件名的选项。还有一个选项用于为每个strace看到的子进程编写一个文本文件。该dialog命令将文本用户界面写入 stdout,但将输出写入 stderr,因此为了将其输出保存到变量(因为var=$(...)管道只接收 stderr)我们需要交换文件描述符

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

但另外,还有--output-fd一个标志,我们也可以利用它。还有命名管道的方法。我建议阅读有关该dialog命令的链接帖子,以了解正在发生的事情的详细描述。

相关内容