如何在上一个非终止命令打印特定字符串后执行命令?

Mar*_* An 2 bash text-processing control-flow

我想执行commandA打印以下内容:

line1
line2
line3
started successfully
line4
...
...
Run Code Online (Sandbox Code Playgroud)

当打印该行时,started successfully我想启动另一个命令(并且可能多路复用它们的输出,以便两者都打印在终端上)。

我怎样才能在 bash 中实现这一目标?

avi*_*iro 5

您可以通过以下一种方法来做到这一点:

$ outputfile=output.log
$ commandA | tee "$outputfile" & tail --pid=$! -n+1 -f "$outputfile" |grep -q "started successfully" && commandB; wait
Run Code Online (Sandbox Code Playgroud)

解释:

  1. 使用该tee命令将输出写入 STDOUT 和名为$outputfile.
  2. 您在后台运行该命令,因此您现在可以跟踪其输出。
  3. tail --pid=$! -n+1 -f "$outputfile"- 您运行tail命令$outputfile并从第一行开始跟踪其输出。
    • --pid=$!需要该标志来确保tail命令一旦commandA完成就终止。
  4. grep -q "started successfully"- 将在第一次出现所需字符串时成功(安静地)退出。
  5. && commandB- 如果grep找到该字符串,它将执行commandB
    • 您应该使用&&and not;来确保 当在 的输出中找到该字符串时才commandB执行。如果在未写入此字符串的情况下完成(例如,如果失败),则您不想运行第二个命令。commandAcommandA
  6. wait- 如果commandB之前完成,则在返回 shell 之前 commandA继续等待运行。commandA
    • 或者,如果之前完成,您可以运行fg而不是waitcommandA继续在前台运行。commandB

更新

受到 @PaulPazderski 答案的启发,这是另一种无需日志文件和命令的方法tail

$ commandA | tee >(grep -q "started successfully" && commandB; cat >/dev/null)
Run Code Online (Sandbox Code Playgroud)

唯一的缺点是,如果在之前commandA完成,shell 将在完成后立即返回到提示符,同时可能仍在后台运行,甚至将输出写入终端。 commandBcommandAcommandB

为了解决这个问题,只需将最终输出通过管道传输到另一个命令,例如cat,以确保只有当没有任何内容写入 stdout 时 shell 才会返回到提示符(这意味着整个命令已完成,甚至是commandB)。

$ commandA | tee >(grep -q "started successfully" && commandB; cat >/dev/null) | cat
Run Code Online (Sandbox Code Playgroud)