首页 文章

当/ dev / null对普通用户不可写时,如何重定向stdout / stderr

提问于
浏览
-1

如何暂时禁用bash脚本中的stdout或stderr?

当然最常见的方法是将stdout或stderr重定向到/ dev / null .
但在某些系统上,/ dev / null对于普通用户来说可能是不可写的 .
我正在编写一些旨在可移植的脚本,所以我不喜欢使用/ dev / null

一些博客/帖子说>& - 可以关闭stdout,但是当我在bash终端中尝试回显123>& - 时,它刚刚失败并显示消息"bash: echo: write error: Bad file descriptor"

当然我可以通过将stdout或stderr重定向到这样的tmp文件来实现:
some_command> / tmp / null
但我想要的是更多"elegant"方式

我想也许我可以通过使用这样的管来实现这一点:
some_command | :

但通过这种方式,它可能会“污染”原始命令的退出代码

2 回答

  • 0

    这是一种可能的方法来做你想要的:

    ( my_cmd 3>&1 1>&2 2>&3- ) | :
    

    这会暂时将 stdout 发送到新文件句柄 3 并将 stderr 重定向到 stdout ,以便 stderr 管道进入命令(在本例中为 : ) . 然后将新文件句柄路由回 stdout . 这些避免将 my_cmdmy_cmd 输入 : . - 在使用后关闭句柄 .

    要在上面检查 my_cmd 的存在状态,请检查环境变量 $PIPESTATUS[0] . $PIPESTATUS 是一个 bash 环境数组变量,它保存最后一个管道中每个管道命令的退出状态 .

    我认为真正正确的答案是调查为什么 /dev/null 不是世界可写的 . 不是这样的是非标准的系统配置,可能会导致系统问题 . 相比之下,上述解决方法有点混乱 .

  • 0

    根据我之前写的内容和@nos上面的评论,这是一个例子:

    (假设您当前目录中没有名为'zzz'的文件,并且' . '可读)

    #!/bin/bash
    set -o pipefail
    ls . 2>&1 |:
    echo $?
    ls zzz 2>&1 |:
    echo $?
    

    管道成功并以静默方式失败并维护退出代码 . 请注意,您可能仍然可以创建一个管道示例,但这不会产生所需的结果 . 我还没想出一个,但这并不意味着它不在那里 . 正如许多人已经指出的那样,最好的答案是修复系统,使/ dev / null是世界可写的 .

    EDIT :将/ bin / sh更改为/ bin / bash,虽然这可能不是针对真正的Bourne Shell进行测试的,但我决定谨慎行事 .

    EDIT :另一个脚本,显示了几种不同的重定向,并使用了 2>&1 ||& 快捷方式 . 如果你运行它,你会发现一些 ls 失败返回141退出状态而不是预期的2.这是一个破坏的管道退出状态,但仍然代表一个失败 .

    #!/bin/bash
    set -o pipefail
    # start with commands that should succeed
    # redirect everything to ':'
    echo "ls . |& :"
    ls . |& :
    echo $?
    # redirect only stdout to ':'
    echo "ls . | :"
    ls . | :
    echo $?
    # redirect only stderr to ':'
    echo "((ls . 1>&3) |& : ) 3>&1"
    ((ls . 1>&3) |& : ) 3>&1
    echo $?
    # now move to failures
    # redirect everything to ':'
    echo "ls zzz |& :"
    ls zzz |& :
    echo $?
    # redirect only stdout to ':'
    echo "ls zzz |:"
    ls zzz |:
    echo $?
    # redirect only stderr to ':'
    echo "((ls zzz 1>&3) |& : ) 3>&1"
    ((ls zzz 1>&3) |& : ) 3>&1
    echo $?
    

    当我试图摧毁stdout但保持stderr时,我使用了两个子shell . 你可以在没有外层的情况下做到这一点 . 事实上,这可能会更好 . 您可以获得1退出状态,而不是获得损坏的管道错误 .

相关问题