失败后如何继续级联管道命令

Bis*_*hoy 5 bash pipe error-handling

我正在运行一个命令并使用我自己的脚本操作输出,但我不希望主命令在我的脚本失败时停止。

例如:

a-command | tee logfile.txt | myscript
Run Code Online (Sandbox Code Playgroud)

当我的脚本中途失败时,我查看了 logfile.txt,我发现它在我的脚本停止工作的地方中断了,但我想要的是让 a-command 继续运行,让 logfile.txt 拥有完整的日志,以便我可以调试我的脚本并修复错误。

修改我的命令以将最后一个管道部分视为可选或在出现错误时忽略的方法是什么,以便前两个部分(命令和 tee)完成他们的工作。

[编辑]a-command是一项冗长的任务,我的脚本基本上是在命令运行时操纵输出以更好地报告状态。所以我不想在a-command完成它的工作后运行我的脚本。

Pau*_*ant 10

Tee(在 Linux 中)有一个忽略管道故障的选项。

a-command | tee --output-error=warn logfile.txt | myscript
Run Code Online (Sandbox Code Playgroud)

当 myscript 失败或被杀死时,a-command 继续运行并且日志继续增长。

您可以重新运行脚本,并在它赶上日志的最后一个完整块时退出:

myscript < logfile.txt
Run Code Online (Sandbox Code Playgroud)

您可以重新运行您的脚本,并让它在赶上时等待添加。

tail -999999f < logfile.txt | myscript
Run Code Online (Sandbox Code Playgroud)

一个更复杂的例子,包含在一个 Bash 脚本中。

logger 代表您的命令。它生成一个短字符串的 36 个排列,每秒一个。所有输出都被传送到 593580.log。

awk 代表你的“myscript”。它打印输入的一个子集。

wdog 是我的看门狗实用程序。-d 5 使其调试其操作。-t 25 使其在 25 秒后超时受控制的进程(awk),并带有 SIGUSR1。这只是节省了我手动运行 kill 来模拟您的脚本失败——我喜欢可重复的测试。

当 awk 消失时,同一复合命令中的 cat 会读取管道,并将剩余数据复制到重复日志中。因此,您可以针对完整日志或仅针对未处理的数据重新运行脚本,并且可以比较两个日志以准确找到崩溃的位置。

或者,您可以cat >/dev/null,只是为了保持管道处于活动状态,以便记录器继续运行。

两个日志文件副本似乎都是行缓冲的:tail -f 然后实时显示。

示例脚本:

#! /bin/bash

logger () {

    for Q in {0..1}{A..C}{A..F}; do
        printf '%s\n' "${Q}"
        sleep 1
    done
}
    
AWK='
/C/ { printf ("awk %d %s\n", NR, $0); }
'

    logger | tee 593580.log | 
        { 
            date
            wdog -d 5 -t 25 awk "${AWK}"
            date
            cat > 593580.add 
            date
        }
Run Code Online (Sandbox Code Playgroud)

测试运行:

paul $ ./593580
Thu 18 Jun 15:35:24 BST 2020
wdog       25.000| Thu Jun 18 15:35:49.574 2020
wdog 15:35:24.574| Started awk as 14035
awk 3 0AC
wdog 15:35:29.579| Tick
awk 9 0BC
wdog 15:35:34.583| Tick
awk 13 0CA
awk 14 0CB
awk 15 0CC
wdog 15:35:39.586| Tick
awk 16 0CD
awk 17 0CE
awk 18 0CF
wdog 15:35:44.591| Tick
awk 21 1AC
wdog 15:35:49.579| Tick
wdog 15:35:49.579| Timed out child 14035 with signal 10
wdog 15:35:49.580| Child 14035 terminated with signal 10
Thu 18 Jun 15:35:49 BST 2020
Thu 18 Jun 15:36:00 BST 2020
paul $ 
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 10

a-command | tee logfile.txt | { myscript; cat >/dev/null; }
Run Code Online (Sandbox Code Playgroud)

这将首先像往常一样运行您的管道,直到myscript终止(无论出于何种原因)。那时,cat将接管读取,tee直到没有更多数据到达。cat通过管道将其读取的数据丢弃到/dev/null

如果a-command在没有先myscript结束/失败的情况下完成,myscript将无法读取更多数据并且可能会终止(?)。在myscript终止时cat启动,但由于没有更多数据要读取,它将立即终止并完成管道。


解决 TooTea关于确保我们仍然获得管道的正确退出状态的评论

a-command | tee logfile.txt | ( myscript; err=$?; cat >/dev/null; exit "$err" )
Run Code Online (Sandbox Code Playgroud)