我必须多次调用一个不灵活的外部工具,该工具将一些输入数据作为参数,并将输出文件作为参数写入处理数据,例如:
some_prog() { echo "modified_$1" > "$2"; }
对于不同的输入,我想调用some_prog,过滤输出并将所有调用的输出写入同一文件" out_file"。另外,我想在每次调用some_prog之前向输出文件添加标题行。给出以下虚拟过滤器:
slow_filter() {
read input; sleep "0.000$(($RANDOM % 10))"; echo "filtered_$input"
}
我写了以下代码:
rm -f out_file
for input in test_input{1..8}; do
echo "#Header_for_$input" >> "out_file"
some_prog $input >( slow_filter >> "out_file" )
done
但是,这将产生一个像这样的out_file:
#Header_for_test_input1
#Header_for_test_input2
#Header_for_test_input3
#Header_for_test_input4
#Header_for_test_input5
#Header_for_test_input6
#Header_for_test_input7
#Header_for_test_input8
filtered_modified_test_input4
filtered_modified_test_input1
filtered_modified_test_input2
filtered_modified_test_input5
filtered_modified_test_input6
filtered_modified_test_input3
filtered_modified_test_input8
filtered_modified_test_input7
我预期的输出是:
#Header_for_test_input1
filtered_modified_test_input1
#Header_for_test_input2
filtered_modified_test_input2
#Header_for_test_input3
filtered_modified_test_input3
#Header_for_test_input4
filtered_modified_test_input4
#Header_for_test_input5
filtered_modified_test_input5
#Header_for_test_input6
filtered_modified_test_input6
#Header_for_test_input7
filtered_modified_test_input7
#Header_for_test_input8
filtered_modified_test_input8
我意识到>()进程替换了shell。有没有办法同步子壳的输出?或者这个问题有另一个优雅的解决方案吗?我想避免在每次迭代中写入不同文件的明显方法,因为在我的代码中,for循环有几十万次迭代。
答案 0 :(得分:1)
将头写入进程替换,特别是在带有过滤器的命令组中,以便将连接的输出作为一个流写入out_file
。
rm -f out_file
for input in test_input{1..8}; do
some_prog "$input" >( { echo "#Header_for_$input"; slow_filter; } >> "out_file" )
done
由于进程替换是真正异步的,并且在执行循环的下一次迭代之前似乎没有办法等待它完成,我会使用一个显式的命名管道。
rm -f out_file pipe
mkfifo pipe
for input in test_input{1..8}; do
some_prog "$input" pipe &
echo "#Header_for_$input" >> out_file
slow_filter < pipe >> out_file
done
(如果some_prog
由于某种原因无法使用命名管道,则可以使用常规文件。在这种情况下,您不应该在后台运行该命令。)
答案 1 :(得分:1)
由于chepner使用命名管道的方法在我的“真实世界脚本”中似乎非常慢(比此解决方案慢约10倍),实现我想要的最简单,最安全的方法似乎是一个临时文件: / p>
rm -f out_file
tmp_file="$(mktemp --tmpdir my_temp_XXXXX.tmp)"
for input in test_input{1..8}; do
some_prog "$input" "$tmp_file"
{
echo "#Header_for_$input"
slow_filter < "$tmp_file"
} >> out_file
done
rm "$tmp_file"
这样,临时文件tmp_file
在每次迭代中都会被覆盖,这样如果系统的临时目录是RAM磁盘,它就可以保存在内存中。