当我使用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
这里的关键点是
使用
-p
它将导致tee
警告写入任何输出而不是管道的错误。这意味着 EPIPE 错误fwrite
不会导致tee
退出,并且tee
只要至少有一个打开的输出文件可供写入,就会运行。如果您想获得有关打印到 stderr 的 EPIPE 警告,请--output-error=warn
改用-p
.用于
> >(head -c1 | wc -c )
将 tee 的标准输出重定向到另一个>(process substitution)
.这很重要,原因有二。您需要处理由tee
.>/dev/null
例如,如果您使用,tee
只要 stdin 有数据就会运行(在这种情况下永远运行)。同时,它将允许>(process substitution)
将输出发送到标准输出以进行进一步处理。其他可能性但不是那么优雅的是通过其他方式关闭tee
stdout 输出。两种可能性是>/dev/full
和>&-
。但是,这些将发出警告(分别是 tee:标准输出:设备上没有剩余空间和 tee:标准输出:错误的文件描述符)