Tee >( process ) 在写入文件时截断其标准输出

Tee >( process ) 在写入文件时截断其标准输出

当我使用tee管道将 stdout 直接传输到“特定代码块”(然后将修改后的数据写入文件)时,我总是会获得文件中预期输出行的完整补充。

但是,当我将tee相同的数据发送到进程时>("same block of code"),它可能会从输出中删除最多 4 行。这个数字各不相同;有时它会写出所有行。

我该如何解决这个问题,以及为什么它只发生在吗>( process )

更多信息:当发生此行丢失时,我正在“tee”到 2 个进程替换以及正常的标准输出管道。

在 Ubuntu 10.04.2 LTS 上使用 GNU bash,版本 4.1.5(1)-release (i486-pc-linux-gnu)。

这是实际的脚本。第二个过程替代是有问题的过程,即以>(tr $'\x60' $X01

#  
# Run 'locate' and direct the output to a temp file
  errflag=""
  locitmct=0  # Count of located items 
  columns=4  # The number of columns in the main dialog
  colmnb=0  # Column number (NB: columns 1 and 2 are processed together) 
  X01=$'\x01'
  eval locate $zenargs |tee \
      >(zenity --progress --pulsate --auto-close) \
      >(tr $'\x60' $X01 \
         |sed -n "s/^\(.*\/\)\(.*\)/\1\2\n\2\n\1/p" \
            |while IFS= read -r line ; do \
              #
              #
              # process the data
              #
              #
            done > "$listf" )\
      >/dev/null
#
cat "$listf"
#

答案1

自从我提出这个问题以来已经过去了 10 个小时,我已经找到了解决方案... 注意:正如我之前在评论中提到的(在问题下),wait不适用于这些进程。我认为这是因为这些“进程替代”不是“子”进程,我相信这是wait等待的。 (我尝试过wait没有参数)....

对其功能和缺点的评论将不胜感激。我不太明白 stdin 是如何被拾取的zenity以及tr何时echo是第一个命令,但我只是想尝试一下......它似乎有效(在本例中),但这种方法安全吗?

很可能有一些经过充分尝试和测试的方法可以解决这个问题,所以其他答案是值得的......


#!/bin/bash
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Set up flag-files for processes to send PIDs to main process
# The first thing each process does is: echo -n "$BASHPID " > flag-file  
for i in {1..2};do cp /dev/null "$listf".pid$i;done
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
eval locate $zenargs |tee \
    >(echo -n "$BASHPID " > "$listf".pid1 ; \
      zenity --progress --pulsate --auto-close) \
    >(echo -n "$BASHPID " > "$listf".pid2 ; \
      tr $'\x60' $X01 \
       |sed -n "s/^\(.*\/\)\(.*\)/\1\2\n\2\n\1/p" \
          |while IFS= read -r line ; do \
              #
              #
              # process the data 
              #
              #
          done > "$listf" ) \
    >/dev/null
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
####  WAIT for processes to terminate  
pids=$(cat "$listf".pid{1,2})
while [[ "$pids" == *[0-9]* ]] ; do
   sleep .1 # GNU
   for pid in $pids ; do
      if ! kill -0 "$pid" 2>/dev/null; then
         pids="${pids/$pid/}"
      fi
   done 
done
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
cat "$listf"
#

答案2

从 coreutils 8.24 版本开始,还有另一种方法:

tee -p </dev/zero >(head -c10M | wc -c ) > >(head -c1 | wc -c ) | numfmt --to=iec

输出是

1

10M

这里的关键点是

  1. 使用-p它将导致tee警告写入任何输出而不是管道的错误。这意味着 EPIPE 错误fwrite不会导致tee退出,并且 tee只要至少有一个打开的输出文件可供写入,就会运行。如果您想获得有关打印到 stderr 的 EPIPE 警告,请--output-error=warn改用-p.

  2. 用于> >(head -c1 | wc -c )将 tee 的标准输出重定向到另一个>(process substitution).这很重要,原因有二。您需要处理由tee.>/dev/null例如,如果您使用,tee只要 stdin 有数据就会运行(在这种情况下永远运行)。同时,它将允许>(process substitution)将输出发送到标准输出以进行进一步处理。其他可能性但不是那么优雅的是通过其他方式关闭teestdout 输出。两种可能性是>/dev/full>&-。但是,这些将发出警告(分别是 tee:标准输出:设备上没有剩余空间和 tee:标准输出:错误的文件描述符)

相关内容