【问题标题】:Bash script - store stderr in a variable [duplicate]Bash脚本 - 将stderr存储在变量中[重复]
【发布时间】:2011-03-09 00:08:40
【问题描述】:

我正在编写一个脚本来备份数据库。我有以下行:

mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb | gzip > $filename

我想将 stderr 分配给一个变量,以便它会向我自己发送一封电子邮件,让我知道如果出现问题会发生什么。我找到了将标准错误重定向到标准输出的解决方案,但我不能这样做,因为标准输出已经(通过 gzip)发送到文件。如何将 stderr 单独存储在变量 $result 中?

【问题讨论】:

    标签: bash scripting redirect stdout stderr


    【解决方案1】:

    尝试将 stderr 重定向到 stdout 并使用 $() 捕获它。换句话说:

    VAR=$((your-command-including-redirect) 2>&1)
    

    由于您的命令将标准输出重定向到某处,因此它不应干扰标准错误。可能有一种更简洁的方式来编写它,但这应该可以。

    编辑:

    这确实有效。我已经测试过了:

    #!/bin/bash                                                                                                                                                                         
    BLAH=$((
    (
    echo out >&1
    echo err >&2
    ) 1>log
    ) 2>&1)
    
    echo "BLAH=$BLAH"
    

    将打印BLAH=err 并且文件log 包含out

    【讨论】:

    • @AdamCrume 我将如何更改此脚本,以便在日志文件中我将同时拥有 stderr 和 stdout ( out \n err )
    • @kobymeir:最简单的方法是先使用foo > out.log 2> err.log,然后再使用cat out.log err.log > combined.log。为避免破坏当前目录中的文件,您想使用mktemp在/tmp中创建out.log和err.log,然后将它们删除。
    • @AdamCrume 但是使用这些技术我不会有标准错误,标准输出不会按照它们出现的正确顺序。如果我有:echo err1 >&2 echo out >&1 echo err2 >&2 我希望日志为:err1 out err2,错误变量将为:err1 err2
    • @kobymeir:我认为这就是你想要的,因为你指定了(out \n err)。如果你想让它们交错,那就更简单了:myvar=$(foo 2>&1)
    • @AdamCrume 好的,我的观点不够清楚,一方面我希望它们交错,另一方面我想将所有标准错误捕获到$error 变量中。
    【解决方案2】:

    dd 同时写入标准输出和标准错误:

    $ dd if=/dev/zero count=50 > /dev/null 
    50+0 records in
    50+0 records out
    

    这两个流是独立的并且可以单独重定向:

    $ dd if=/dev/zero count=50 2> countfile | wc -c
    25600
    $ cat countfile 
    50+0 records in
    50+0 records out
    $ mail -s "countfile for you" thornate < countfile
    

    如果你真的需要一个变量:

    $ variable=`cat countfile`
    

    【讨论】:

      【解决方案3】:

      您可以在将 stdout 引用重定向到另一个文件号(例如 3)之前保存它,然后将 stderr 重定向到那个:

      result=$(mysqldump --user=$dbuser --password=$dbpswd  \
         --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename)
      

      所以3&gt;&amp;1 会将文件号 3 重定向到标准输出(注意这是在标准输出被管道重定向之前)。然后2&gt;&amp;3 将stderr 重定向到文件号3,现在与stdout 相同。最后通过输入管道重定向标准输出,但这不会影响文件号 2 和 3(请注意,从 gzip 重定向标准输出与 mysqldump 命令的输出无关)。

      编辑:更新了从mysqldump 命令而不是gzip 重定向stderr 的命令,我的第一个答案太快了。

      【讨论】:

        【解决方案4】:

        对于 Bash 中的任何通用命令,您可以执行以下操作:

        { error=$(command 2>&1 1>&$out); } {out}>&1
        

        常规输出正常显示,stderr 的任何内容都被捕获在 $error 中(在使用它来保留换行符时将其引用为“$error”)。要将标准输出捕获到文件中,只需在末尾添加重定向,例如:

        { error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output
        

        分解,从外向内阅读:

        • 为整个块创建文件描述 $out,复制标准输出
        • 在 $error 中捕获整个命令的标准输出(但见下文)
        • 该命令本身将 stderr 重定向到 stdout(已在上面捕获),然后将 stdout 从块外部重定向到原始 stdout,因此只有 stderr 被捕获

        【讨论】:

        • 在 bash v3.2 中不起作用:unexpected token `{out}'。这种语法需要 Bash 4 吗?
        • 它在 bash 4.2 和 4.1 中运行良好,我什至尝试了 shopts:compat32、compat31,它也运行良好,也许这是 3.2 中的一个错误,因为当 bash 处于兼容模式时有效,除非兼容性仅包含不会由于 4.2 而损坏的项目,而不是 4.2 的一部分的功能......(我认为现在大多数人都使用 4.2 对吗?)无论如何这是一个旧帖子,但只是为了清除它出来了,它确实有效,这正是我需要在屏幕上显示普通文本时将错误分配给变量...:)
        • 一个优秀而优雅的解决方案。只需添加一件事:之后您需要关闭文件描述符:exec {out}&gt;&amp;-
        猜你喜欢
        • 2021-08-19
        • 2015-08-06
        • 2016-07-10
        • 2017-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多