【问题标题】:How to redirect output to a file and stdout如何将输出重定向到文件和标准输出
【发布时间】:2010-09-29 22:52:57
【问题描述】:

在 bash 中,调用 foo 会在标准输出上显示该命令的任何输出。

调用foo > output 会将来自该命令的任何输出重定向到指定的文件(在本例中为“输出”)。

有没有办法将输出重定向到一个文件让它显示在标准输出上?

【问题讨论】:

  • 如果有人刚刚在这里寻找捕获错误输出到文件,请查看 - unix.stackexchange.com/questions/132511/…
  • 关于术语的注释:当您执行foo > output 时,数据写入标准输出,而标准输出名为output 的文件。也就是说,写入文件就是写入标准输出。您在问是否可以同时写入标准输出和终端。
  • @WilliamPursell 我不确定您的澄清是否会改善 :-) 这个怎么样:OP 询问是否可以将 被调用程序的 标准输出指向文件和调用程序的标准输出(后者是被调用程序将继承的标准输出,如果没有做任何特别的事情;即终端,如果调用程序是交互式 bash 会话)。也许他们也想以类似的方式引导被调用程序的stderr(“该命令的任何输出”可能被合理地解释为包括stderr)。

标签: linux bash file-io io stdout


【解决方案1】:

你想要的命令被命名为tee

foo | tee output.file

例如,如果你只关心标准输出:

ls -a | tee output.file

如果您想包含标准错误,请执行以下操作:

program [arguments...] 2>&1 | tee outfile

2>&1 将通道 2(stderr/标准错误)重定向到通道 1(stdout/标准输出),这样两者都写为 stdout。从tee 命令开始,它也被定向到给定的输出文件。

此外,如果您想追加到日志文件,请使用tee -a

program [arguments...] 2>&1 | tee -a outfile

【讨论】:

  • 如果 OP 想要重定向“所有输出”,您还需要获取标准错误:“ls -lR / 2>&1 | tee output.file”
  • @evanmcdonnal 答案没有错,只是可能不够具体,或者根据您的要求不完整。在某些情况下,您可能不希望将 stderr 作为输出的一部分保存到文件中。当我 5 年前回答这个问题时,我认为 OP 只想要标准输出,因为他在帖子的主题中提到了标准输出。
  • 啊抱歉,我可能有点糊涂了。当我尝试它时,我只是没有输出,也许这一切都将进入标准错误。
  • tee 上使用-a 参数将内容附加到output.file,而不是覆盖它:ls -lR / | tee -a output.file
  • 如果你之后使用$?,它会返回tee的状态码,这可能不是你想要的。相反,您可以使用${PIPESTATUS[0]}
【解决方案2】:
$ program [arguments...] 2>&1 | tee outfile

2>&1 转储 stderr 和 stdout 流。 tee outfile 获取它获取的流并将其写入屏幕和文件“outfile”。

这可能是大多数人正在寻找的。可能的情况是某些程序或脚本长时间工作并产生大量输出。用户希望定期检查它的进度,但也希望将输出写入文件。

问题(尤其是在混合 stdout 和 stderr 流时)是依赖于程序刷新的流。例如,如果对 stdout 的所有写入都刷新,但对 stderr 的所有写入都刷新,那么它们最终将在输出中不按时间顺序排列文件和屏幕上。

如果程序每隔几分钟只输出 1 或 2 行来报告进度,这也很糟糕。在这种情况下,如果程序没有刷新输出,用户甚至在几个小时内都不会在屏幕上看到任何输出,因为在几个小时内都不会通过管道推送。

更新:unbuffer 程序是expect 包的一部分,将解决缓冲问题。这将导致 stdout 和 stderr 立即写入屏幕和文件,并在合并和重定向到 tee 时使它们保持同步。例如:

$ unbuffer program [arguments...] 2>&1 | tee outfile

【讨论】:

  • 有人知道 osx 的“unbuffer”吗?
  • 如果您不能使用 unbuffer,GNU coreutils 包含一个名为 stdbuff 的工具,可用于防止像 $ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile 这样的输出缓冲
  • 如果您使用的是 OS X,在大多数情况下使用 unbuffer 会稍微容易一些,但如果您想将信号传递给正在运行的命令,则不是这样。我的评论更针对使用 Linux 的用户,其中最有可能默认安装 coreutils。 @Ethan,如果您对 stdbuf 语法感到困惑,请参阅此答案:stackoverflow.com/a/25548995/942781
  • 请注意,python 有一个内置选项 -u 可以取消缓冲输出。
  • 训练 ML 模型的绝对救星,我想在没有额外代码的情况下记录,但也可以在运行所需的几小时/几天内查看输出,谢谢!
【解决方案3】:

另一种对我有用的方法是,

<command> |& tee  <outputFile>

gnu bash manual所示

例子:

ls |& tee files.txt

如果使用了‘|&’,command1的标准错误,除了它的标准输出,还通过管道连接到command2的标准输入;它是 2>&1 | 的简写。标准错误到标准输出的这种隐式重定向是在命令指定的任何重定向之后执行的。

更多信息,请参考redirection

【讨论】:

  • 如果你之后使用$?,它会返回tee的状态码,这可能不是你想要的。相反,您可以使用${PIPESTATUS[0]}
  • 此方法丢弃彩色控制台输出,有什么想法吗?
  • 尝试:unbuffer ls -l --color=auto |三通文件.txt
【解决方案4】:

您可以主要使用Zoredachesolution,但如果您不想覆盖输出文件,您应该使用 -a 选项编写 tee,如下所示:

ls -lR / | tee -a output.file

【讨论】:

    【解决方案5】:

    要补充的东西...

    软件包 unbuffer 对 fedora 和 redhat unix 版本下的某些软件包有支持问题。

    抛开烦恼

    以下对我有用

    bash myscript.sh 2>&1 | tee output.log
    

    谢谢ScDFmatthew 你的输入为我节省了很多时间..

    【讨论】:

      【解决方案6】:

      使用tail -f output 应该可以工作。

      【讨论】:

        【解决方案7】:

        您可以通过在脚本开头使用类似的内容来为整个脚本执行此操作:

        #!/usr/bin/env bash
        
        test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }
        
        # do whaetever you want
        

        这会将 stderr 和 stdout 输出重定向到名为 mylogfile 的文件让所有内容同时进入 stdout

        它使用了一些愚蠢的技巧:

        • 使用不带命令的exec 来设置重定向,
        • 使用tee 复制输出,
        • 使用所需的重定向重新启动脚本,
        • 使用特殊的第一个参数($'string' 特殊 bash 表示法指定的简单 NUL 字符)来指定脚本重新启动(您的原始作品可能无法使用等效参数),
        • 尝试使用pipefail 选项重新启动脚本时保留原始退出状态。

        丑陋但在某些情况下对我有用。

        【讨论】:

          【解决方案8】:

          因为这个用例把我带到了这里,所以得到了奖励:

          如果您需要以其他用户的身份执行此操作

          echo "some output" | sudo -u some_user tee /some/path/some_file
          

          请注意,回显将在您发生时发生,文件写入将以“some_user”发生,如果您以“some_user”身份运行回显并使用 > 重定向输出,那么会起作用> "some_file" 因为文件重定向会发生在你身上。

          提示:tee 还支持附加 -a 标志,如果您需要将文件中的一行替换为另一个用户,您可以作为所需用户执行 sed。

          【讨论】:

            【解决方案9】:

            &lt; command &gt; |&amp; tee filename # 这将创建一个以命令状态为内容的文件“文件名”,如果文件已经存在,它将删除现有内容并写入命令状态。

            &lt; command &gt; | tee &gt;&gt; filename # 这会将状态附加到文件中,但不会在标准输出(屏幕)上打印命令状态。

            我想通过在屏幕上使用“回显”来打印一些东西,并将回显的数据附加到文件中

            echo "hi there, Have to print this on screen and append to a file" 
            

            【讨论】:

              【解决方案10】:

              在我的例子中,我有带有输出日志的 Java 进程。显示输出日志并将它们重定向到文件(此处命名为 logfile)的最简单解决方案是:

              my_java_process_run_script.sh |& tee logfile
              

              结果是 Java 进程正在运行并显示输出日志,并且 将它们放入名为 logfile 的文件中

              【讨论】:

                【解决方案11】:

                tee 非常适合这个,但这也可以完成这项工作

                ls -lr / > output | cat output
                

                【讨论】:

                • 如果输出不存在并且它不会做你想做的事情,那么这是一个错误,总的来说这是荒谬的。也许你的意思是“;”而不是“|” ?
                • 即使你使用;,在执行慢速命令时输出也会延迟很多。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-08-31
                • 1970-01-01
                • 2017-08-08
                • 2015-05-23
                • 1970-01-01
                相关资源
                最近更新 更多