bash 可以从两个单独的命令使用相同的 fifo 吗?

bash 可以从两个单独的命令使用相同的 fifo 吗?

我有一个巨大的数据源,我正在使用一些greps 进行过滤。

这基本上就是我现在正在做的事情:

#!/bin/bash
param1='something'
param2='another'
param3='yep'
echo $(avro-read /log/huge_data | grep $param1 | grep "$param2-" | grep $param3 | wc -l) / $(avro-read /log/ap/huge_data | grep $param1 | grep -v "$param2-" | grep $param3 | wc -l) | bc -l

请注意,我做了两次基本相同的过滤(第二次只有一个差异),计算每次的计数,然后除以最终结果。这绝对是一件不靠谱的事情,但我想尝试加快一点速度,只执行一次初始过滤,而不使用临时文件。

我尝试使用 fifo,但我不确定是否可以在一个脚本中让两个进程从中读取数据,以及让第三个进程“等待”直到两个进程都完成计算最终结果。我也研究过使用,但tee还是不确定如何同步生成的子进程。

编辑:自己解决了这个问题https://superuser.com/a/561248/43649,但将另一个建议标记为答案。

答案1

如果您只是想避免创建临时文件(或将 grep 的输出存储在变量中),您可以将其提供给 for 循环,如下所示:

#!/bin/bash

IFS=$'\n'
yay=0
nay=0

for line in `avro-read /log/huge_data | grep $param1 | grep $param3`; do
    [[ $line =~ $param2- ]] && yay=$(($yay + 1)) || nay=$(($nay + 1))
done

echo $yay / $nay \* 100 | bc -l

unset IFS

我已经创建了该方法的修改版本你自己回答不需要临时文件:

#!/bin/bash

(avro-read /log/huge_data | grep $param1 | grep $param3 | tee \
     >(echo yay=`grep -c "$param2-"`) \
     >(echo nay=`grep -vc "$param2-"`) \
     >/dev/null | cat ; echo 'echo $yay / $nay \* 100 | bc -l') | sh

各个命令的输出grep -cecho命令被打印为

yay=123
nay=456
echo $yay / $nay \* 100 | bc -l

避免竞争条件1.通过管道sh执行打印的命令。

1无论哪个grep -c命令先完成,都会打印第一行输出。

答案2

我最终像这样解决了这个问题:

#!/bin/bash
param1='something'
param2='another'
param3='yep'

avro-read /log/huge_data | grep $param1 | grep $param3 \
| tee \
>(grep "$param2-" | wc -l | tr -d '\n' > has_count) \
>(grep -v "$param2-" | wc -l | tr -d '\n' > not_count) \
> /dev/null

echo $(cat has_count | tr -d '\n') '/' $(cat not_count | tr -d 'n') '* 100' | bc -l

因此,我不再依赖 fifo 或临时文件,而是tee将流拆分为两个单独的进程,每个进程只输出一个计数!这样,我就不需要在尝试划分计数之前尝试同步这两个进程。

答案3

嗯,zsh有一个名为 MULTIOS 的功能。这样就可以将一个进程连接到两个 fifo。如果这是一个选项,这里有一个小演示:

#!/bin/zsh -f

setopt multios

mkfifo f1 f2 2> /dev/null

param1='something'
param2='another'
param3='yep'

{ avro-read /log/huge_data | grep $param1 | grep $param3 } > f1 > f2 &

( cat f1 | grep $param2 | wc -l > value1 ) &!
value2=$(cat f2 | grep -v $param2 | wc -l)

print $(( 1. * $( cat value1 ) / $value2 ))

rm value1

然而,我无法找到一种方法来绕过临时文件的创建value1,正如 Dennis 指出的那样,这应该可以避免。但也许你会喜欢这个解决方案。

相关内容