如果我将输出通过管道传输到 tee,则无法“继续”

Posted

技术标签:

【中文标题】如果我将输出通过管道传输到 tee,则无法“继续”【英文标题】:Can't "continue" if I pipe output to tee 【发布时间】:2020-02-05 00:39:35 【问题描述】:

我有一个 bash 脚本,它使用以下结构几乎可以完成我想要的工作:

for x in 1 2 3
do
  
  [[ $x -ne 2 ]] || continue
  echo $x
   &>> foo.log
done

我需要对其进行更改,以便将输出同时发送到终端和日志文件。但是,这不起作用:

for x in 1 2 3
do
  
  [[ $x -ne 2 ]] || continue
  echo $x
   2>&1 | tee -a foo.log
done

看起来,通过创建一个进程,管道阻止我使用continue

当然,我可以在没有continue 的情况下重写我的脚本逻辑,但在我开始之前,我想知道我是否错过了一种更直接的方法来实现我想要的。

【问题讨论】:

管道中的命令在子进程中运行;子进程不能更改父 shell 进程中的控制流(或更改变量,或...)。因此,continuebreakexit 等在管道中无法完全发挥作用。 这就是为什么我说:“通过创建一个流程”。我的问题不是“为什么在这里继续被拒绝”。 【参考方案1】:

您可以将输出重定向到进程替换。

for x in 1 2 3
do
  
  [[ $x -ne 2 ]] || continue
  echo $x
   2>&1 > >(tee -a foo.log)
done |
# I suggest to do pipe the output to ex. `cat`, so that the output 
# of process substitution will be synchronized with rest of the script
cat

但是为什么不直接重定向整个循环的输出呢?

for x in 1 2 3; do
  [[ $x -ne 2 ]] || continue
  echo $x
done 2>&1 | tee -a foo.log

您可以退出子进程。如果你愿意这样做,我建议将 替换为 ( ) 只是为了安全起见,如果你有一天决定删除 tee

for x in 1 2 3
do
  
  [[ $x -ne 2 ]] || exit
  echo $x
   2>&1 | tee -a foo.log
done

【讨论】:

我无法重定向整个循环(其中有一个 cd,因此输出实际上被发送到单独的日志文件)。我喜欢“过程替代”的想法。这是我不熟悉的语法。但是,我不明白“将输出通过管道传输到...”的评论。 “退出”方法有点吓人,但可能是最简单的(有一个大注释要记住不要移除管道)。感谢您的建议。 比较echo 1 > >(sleep 1; tee something)echo 1 > >(sleep 1; tee something) | cat 的输出。问题是>(part) 在后台运行,所以如果它比脚本的其余部分慢,它的输出将与其他命令异步运行。所以echo 1 > >(tee something); echo 2 可能会导致先打印2,然后再打印1。要同步它,请使用管道。 Pipe 确保进程替换在运行下一个命令之前结束。 但是“| cat”重新引入了我要解决的“继续”问题! ;-) 我可能会走“退出”路线...

以上是关于如果我将输出通过管道传输到 tee,则无法“继续”的主要内容,如果未能解决你的问题,请参考以下文章

我可以获取一个输出流,用 tee 复制它,将其中一个复制出来,然后将两者作为输入返回到 diff 中吗?

使用另一个命令通过管道传输时如何读取命令的返回码[重复]

管道命令输出到 tee 但也保存命令的退出代码 [重复]

将 ffmpeg 输出通过管道传输到命名管道

tee命令用法

为啥我的 Python3 脚本不愿将其输出通过管道传输到 head 或 tail(sys 模块)?