bash - sem --wait 在从文件读取的while循环之后不等待
问题描述
我正在尝试在 bash 中使用 GNU 并行来并行运行程序的多个实例,每个实例中都有不同的参数。此外,我希望能够从文件中读取这些参数,并让脚本等待所有并行化作业完成。GNU parallel's parallel --semaphore
akasem
似乎是一种简单的方法来做到这一点。
MCVE
使用文档中基本示例的修改版本sem
,我创建了一个最小的测试用例来说明我的问题:
while read i; do
echo -n "$i "
sem -j 4 "sleep $i && echo $i finished"
done < args.txt
echo
echo 'Started wait'
sem --wait
echo 'Done waiting'
在这里,args.txt
是一个简单包含的文件:
1
2
3
4
预期与实际产出
我希望看到类似于以下内容的输出:
user@host:~$ ./test-sem.sh
1 2 3 4
Started wait
1 finished
2 finished
3 finished
4 finished
Done waiting
然而,令人惊讶的是,sem --wait
实际上并没有等待任务完成,而是得到如下输出:
user@host:~$ ./test-sem.sh
1 2 3 4
Started wait
Done waiting
user@host:~$ 1 finished
2 finished
3 finished
4 finished
也就是说,脚本执行并终止,然后sem
作业在后台运行并打印各自的输出!为什么会这样?在 while 循环中初始化所有作业后,如何才能sem --wait
真正等待?sem
有趣的是,它是从导致问题的文件中读取的,而不是 while 循环本身。也就是说,以下工作按预期工作:
i=1;
while (( $i <= 4 )); do
echo -n "$i "
sem -j 4 "sleep $i && echo $i finished"
let i=i+1
done
echo
echo 'Started wait'
sem --wait
echo 'Done waiting'
但是我的实际用例有一个包含更复杂参数组合的文件,所以我真的很想从文件中读取参数。
解决方案
来自gnu 并行文档:
- 信号
[...]
--semaphore 意味着 --semaphorename
tty
除非指定了 --semaphorename。--semaphorename 名称 --id 名称
使用 name 作为信号量的名称。默认是控制 tty 的名称(从 tty 输出)。
默认值通常在交互使用时按预期工作,但在脚本名称中使用时应设置。$$ 或 my_task_name 通常是一个不错的值。
信号量存储在 ~/.parallel/semaphores/
您必须使用相同的名称才能使信号量相同!以下代码:
while read i; do
tty
done < somefile
tty
输出:
not a tty
/dev/pts/0
一切都在tty
调用stdin。因为标准输入来自文件,所以不再一样。你可以:ttyname
- 手动传递名称
--id <some unique name>
- 使用不同的文件描述符
while read -u 3 ...; do ..; done 3<file
。
推荐阅读
- sql - SQL:一2多行,多行合并为一列
- python - Python程序无异常无提示退出
- javascript - 默认 onClick 事件或 fromEvent(button, 'click')
- javascript - webpack 3:如何配置 webpack 以防止在由另一个 Web 应用程序加载时与其他包发生冲突?
- android - 在库模块中禁用 Firebase 数据收集?
- machine-learning - 逻辑回归机器学习?
- node.js - promis.all 中每个函数需要多少时间?
- javascript - 如何从多个下拉列表中显示已选择的数据库值的值
- c# - 使用 microsoft DI 创建工厂
- r - R 限制采样