【问题标题】:Bash script global redirection with exec and write to screen使用 exec 进行 Bash 脚本全局重定向并写入屏幕
【发布时间】:2013-08-08 16:49:29
【问题描述】:

我有一个大型 bash 脚本,我想将所有 stdout/stderr 全局重定向到一个文件,除了一些进度指示器,例如特定的回显消息。例如,考虑以下脚本

#!/bin/bash

# all stdout and stderr go to out.log
exec &> out.log

special_echo "starting"

# many other commands go here
# which output both the stdout and stderr
# also some special_echo commands in here,
# for example
echo "msg1"
special_echo "middle"
echo "msg2" >&2

special_echo "finished"

当它运行时输出应该是

$ ./script
starting
middle
finished
$

但是,out.log 应该包含

msg1
msg2

如何实现special_echo 功能?我尝试使用文件描述符并对其进行回显,但无法将其显示在屏幕上。

有没有办法在不将重定向附加到每一行或做类似answer 的事情的情况下实现这一点?

【问题讨论】:

    标签: bash


    【解决方案1】:

    是的,使用另一个文件描述符是可行的方法:

    #!/bin/bash
    
    exec 3>&1
    special_echo () {
        echo "$@" >&3
    }
    
    exec &> out.log
    
    special_echo "starting"
    echo "msg1"
    special_echo "middle"
    echo "msg2" >&2
    special_echo "finished"
    

    【讨论】:

    • 完美运行。我先是exec &> out.log,然后是exec 3>&1,现在我发现这是错误的顺序。
    【解决方案2】:

    重定向到 /dev/tty,这是控制终端。也适用于输入。

    【讨论】:

    • 重定向到 /dev/tty 是 POSIX 吗?
    【解决方案3】:

    在脚本开始时,将 stdoutstderr 保存为自定义描述符。

    # all stdout and stderr go to out.log
    exec 3>&1 4>&2 &>out.log
    

    您可以使用3>/dev/stdout 代替3>&1 等等,或者将其拆分为多个exec 重定向行,如果这对您来说更具可读性。

    那么你需要做的就是使用它们

    echo "starting" >&3
    echo "msg1"
    echo "middle"   >&3
    echo "msg2" >&2
    echo "finished" >&3
    

    你不能使用>/dev/stdout,因为它实际上被exec覆盖了,自定义描述符是必要的。

    最好的一点是您仍然可以访问原始的stderr,而/dev/tty 则无法访问

    echo "special error" >&4
    

    如果您需要,您可以完全撤消脚本其余部分的重定向。

    #restore original
    exec >&3 2>&4
    
    echo "this is special now"
    

    没有函数,没有变量,只是工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-16
      • 2011-11-21
      • 1970-01-01
      相关资源
      最近更新 更多