gpt4 book ai didi

bash - 管道命令链,每个命令输出状态为标准错误

转载 作者:行者123 更新时间:2023-12-03 07:36:43 25 4
gpt4 key购买 nike

我在bash脚本中有一连串的管道命令,将标准输出管道传输到标准输入:

prog1 | prog2 | prog3

他们每个都输出一些标准错误。其中有些输出覆盖前一行,有些则不覆盖,有些则两者都覆盖:例如输出几行输出,然后在 shell 程序中有一个更新的“状态栏”。例如,curl可以将下载进度输出为状态栏。

由于状态栏可能在一个进程的输出与另一个进程的输出之间闪烁,因此输出尚不清楚。

有什么办法可以使各种输出更清晰,例如
  • 要弄清楚链中哪个程序的输出行?
  • 要同时显示所有状态栏,而不会闪烁?

  • 闪烁的示例:

    enter image description here

    最佳答案

    对于这个具有挑战性的问题,这里已经给出了有趣的想法,但是到目前为止,我还没有找到完整的解决方案。我会尝试给一个。为了实现这一目标,我首先编写了三个与PO所谈论的prog1 | prog2 | prog3管道相对应的脚本。

    prog1 在错误流上生成由\n分隔的消息,并在标准流上生成数字:

    #!/bin/bash

    cmd=$(basename $0)

    seq 8 |
    while ((i++ < 10)); do
    read line || break
    echo -e "$cmd: message $i to stderr" >&2
    echo $line
    sleep 1
    done

    echo -e "$clearline$cmd: has no more input" >&2

    prog2 生成由 \r分隔的消息,并在错误流上覆盖其自己的输出,并将数字从标准输入流传输到标准输出流:

    #!/bin/bash

    cmd=$(basename $0)
    el=$(tput el)

    while ((i++ < 10)); do
    read line || break
    echo -en "$cmd: message $i to stderr${el}\r" >&2
    echo $line
    sleep 2
    done

    echo -en "$clearline$cmd: has no more input${el}\r" >&2


    最后 prog3 从标准输入流中读取并将消息写入错误流,方法与 prog2相同:

    #!/bin/bash

    cmd=$(basename $0)
    el=$(tput el)

    while ((i++ < 10)); do
    read line || break
    echo -en "$cmd: message $i to stderr${el}\r" >&2
    sleep 3
    done

    echo -en "$clearline$cmd: has no more input${el}\r" >&2

    而不是调用这三个脚本作为

    prog1 | prog2 | prog3

    我们将需要一个脚本来调用这三个程序,将错误流重定向到三个FIFO特殊文件(命名管道),但是在启动此命令之前,我们必须先创建这三个特殊文件并在后台进程中启动以侦听特殊文件:每次发送整行时,这些过程都会将其打印在屏幕的特殊区域,我将其称为任务栏。

    三个任务栏在屏幕的底部:上方的一个包含错误流的 prog1消息,下一个对应于 prog2,底部的最后一个包含 prog3的消息。

    最后,必须删除FIFO文件。

    现在棘手的部分:
  • 在不缓冲以\r结尾的行的情况下,我发现没有实用程序读取,因此在将消息行打印到屏幕上之前,我不得不将\r更改为\n
  • 我正在与管道连接的多个程序中的某个程序正在缓冲其输入或输出,导致消息直到结束才被打印,这显然不是预期的行为;为了解决这个问题,我不得不在stdbuf实用程序中使用tr命令;

  • 放在一起,我实现了下一个脚本,该脚本按预期工作:

    #!/bin/bash

    echo -n "Test with clean output"
    echo;echo;echo # open three blank lines in the bottom of the screen
    tput sc # save the cursor position (bottom of taskbars)
    l3=$(tput rc) # move cursor at last line of screen
    l2=$(tput rc; tput cuu1) # move cursor at second line from bottom
    l1=$(tput rc; tput cuu1; tput cuu1) # move cursor at third line from bottom
    el=$(tput el) # clear to end of line
    c3=$(tput setaf 1) # set color to red
    c2=$(tput setaf 2) # set color to green
    c1=$(tput setaf 3) # set color to yellow
    r0=$(tput sgr0) # reset color

    mkfifo error{1..3} # create named pipes error1, error2 and error3

    (cat error1 | stdbuf -o0 tr '\r' '\n' |
    while read line1; do echo -en "$l1$c1$line1$el$r0"; done &)
    (cat error2 | stdbuf -o0 tr '\r' '\n' |
    while read line2; do echo -en "$l2$c2$line2$el$r0"; done &)
    (cat error3 | stdbuf -o0 tr '\r' '\n' |
    while read line3; do echo -en "$l3$c3$line3$el$r0"; done &)

    ./prog1 2>error1 | ./prog2 2>error2 | ./prog3 2>error3

    wait

    rm error{1..3} # remove named pipes

    tput rc # put cursor below taskbars to finish gracefully
    echo
    echo "Test finished"

    我们使用 tput生成的字符串为任务栏的每一行添加了不同的颜色。

    请享用。

    关于bash - 管道命令链,每个命令输出状态为标准错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61555538/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com