exec重定向混乱了bash中的输出顺序

时间:2016-02-14 01:16:21

标签: bash redirect fifo

我正在使用obj['services']['344']['post']['ID']修改输出。它有效,但输出的顺序搞砸了,我不知道为什么。

在下面的代码中我:

  1. 将一些行输出到正常>(...)
  2. 保存STDOUTSTDOUT
  3. 使用exec和STDERR
  4. 修改STDOUTSTDERR的输出
  5. 将输出发送到新修改的>(..)STDOUT
  6. 还原为原始STDERRSTDOUT
  7. 将输出发送到原始STDERRSTDOUT
  8. 我希望输出看起来像#1,#4,#6,但我得到的是#1,#6,#4

    STDERR

    期望输出看起来像这样:

    #!/bin/bash
    
    # output text to normal STDOUT
    echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
    echo '<html>'
    echo "    <head><title>daily backup script: ${now}</title></head>"
    echo '    <body style="font-family:monospace; font-size: 10px">'
    echo '        <table border="1">'
    
    # save STDOUT and STDERR
    exec 6>&1
    exec 7>&2
    
    # modify STDOUT
    exec 1> >(
        while read line
        do
            echo "            <tr><td>$(date +%Y-%m-%d)</td><td>$(date +%H:%M:%S)</td><td colSPan='5'>${line}</td></tr>" >&6
        done
    )
    
    # modify STDERR
    exec 2> >(
        while read line
        do
            echo "            <tr style='color: red'><td>$(date +%Y-%m-%d)</td><td>$(date +%H:%M:%S)</td><td colSPan='5'>${line}</td></tr>" >&6
        done
    )
    
    # output to new modified STDOUT and STDERR
    echo "test"
    echo "test again" >&2
    date
    
    # revert to original STDOUT and STDERR
    exec 1>&6 6>&-
    exec 2>&7 7>&-
    
    # output text to normal STDOUT
    echo '        </table>'
    echo '    </body>'
    echo '</html>'
    

    但这是实际输出:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head><title>daily backup script: </title></head>
        <body style="font-family:monospace; font-size: 10px">
            <table border="1">
                <tr><td>2016-02-13</td><td>20:08:01</td><td colSPan='5'>test</td></tr>
                <tr style='color: red'><td>2016-02-13</td><td>20:08:01</td><td colSPan='5'>test again</td></tr>
                <tr><td>2016-02-13</td><td>20:08:01</td><td colSPan='5'>Sat Feb 13 20:08:01 EST 2016</td></tr>
            </table>
        </body>
    </html>
    

1 个答案:

答案 0 :(得分:0)

我做的第一件事就是用几行代码创建一个更简单的测试用例版本。它只重定向stdout:

#!/bin/bash
echo 1.message
exec 6>&1
exec 1> >( while read line ; do echo ${line} >&6 ; done )
echo 2.message
exec 1>&6 6>&-
echo 3.message

我猜您希望按此顺序查看输出消息:

1.message
2.message
3.message

但是......不!我能够复制你的问题。如果你在上面运行几行代码,你会得到:

1.message
3.message
2.message

对于在子shell中运行的while-read循环的回送管道问题进行了描述here他们说:

  

...如果在子shell中运行,则充当 ...

为了解决这个问题 - 并按照我猜你期望的顺序生成消息,我确实创建了一个命名管道,将stdout重定向到这个命名管道。然后我做了一个&#34;真正的&#34;子shell并等待它以这种方式完成:

#!/bin/bash 
mypipe=/tmp/$$.tmp
trap "rm -f ${mypipe}" EXIT
mknod ${mypipe} p
echo 1.message
exec 6>&1
cat < ${mypipe} &
exec 1>${mypipe}
echo 2.message
exec 1>&6 6>&-
wait
echo 3.message

哪种产品:

1.message
2.message
3.message