在 macOS 上等待任何子进程退出?
Waiting ANY child process exit on macOS?
我想知道如何在 macOS 中等待任何进程完成,因为 wait -n
不起作用。我有一个脚本做几件事,在某些时候它会进入一个循环,调用另一个脚本到后台以利用一些并行性,但不会超过 X 次,因为它效率不高。因此,在创建新进程之前,我需要等待任何子进程完成。
我看过 this question 但它没有回答“任何”部分,它只是说如何等待特定进程完成。
我曾考虑过存储所有 PID 并主动检查它们是否仍然 运行 ps
,但这是非常草率和耗费资源的。我还考虑过将 bash 升级到更新的版本(如果这在 macOS 中是可能的而不破坏 bash 已经工作的方式),但如果没有其他方法可以实际等待 要完成的任何 过程,这是一个非常基本的功能...有什么想法吗?
我的代码的基本版本如下所示:
for vid_file in $VID_FILES
do
my_script.sh $vid_file other_args &
((TOTAL_PROCESSES=TOTAL_PROCESSES+1))
if [ $TOTAL_PROCESSES -ge $MAX_PROCESS ]; then
wait -n
((TOTAL_PROCESSES=TOTAL_PROCESSES-1))
fi
done
我用既不优雅也不高效的方法来替代 wait -n
:
NUM_PROCC=$MAX_PROCESS
while [ $NUM_PROCC -ge $MAX_PROCESS ]
do
sleep 5
NUM_PROCC=$(ps | grep "my_script.sh"| wc -l | tr -d " \t")
# grep command will count as one so we need to remove it
((NUM_PROCC=NUM_PROCC-1))
done
PS:这个问题可以关闭并与我上面提到的问题合并。我刚刚创建了这个新的,因为 Whosebug 不允许我发表评论或提问...
PS2:我明白我的 objective 可以通过其他方式实现。如果您对特定问题本身没有答案,而是有解决方法,请让其他人回答有关“等待任何”的问题,因为它在将来对 me/everyone 也非常有用。我当然会欢迎并感谢解决方法!
提前致谢!
您似乎只想限制同时处于 运行 的进程数。这是使用 bash <= 4.2
:
的基本方法
#!/bin/bash
MAX_PROCESS=2
INPUT_PATH=/somewhere
for vid_file in "$INPUT_PATH"/*
do
while [[ "$(jobs -pr | wc -l)" -ge "$MAX_PROCESS" ]]; do sleep 1; done
my_script.sh "$vid_file" other_args &
done
wait
这是 bash >= 4.3
版本:
#!/bin/bash
MAX_PROCESS=2
INPUT_PATH=/somewhere
for vid_file in "$INPUT_PATH"/*
do
[[ "$(jobs -pr | wc -l)" -ge "$MAX_PROCESS" ]] && wait -n
my_script.sh "$vid_file" other_args &
done
wait
建议 1:完成指标文件
建议将任务完成指示文件添加到您的 my_script.sh
像这样:
echo "[=10=].$(date +%F_%T).done" >> my_script.sh
并在您的部署脚本中测试完成指示器文件是否存在。
rm "my_script.sh.*.done"
my_script.sh "$vid_file" other_args &
while [[ ! -e "my_script.sh.*.done" ]]; do
sleep 5
done
不要忘记清理完成指示器文件。
这种方法的优点:
- 简单
- 所有 shell 都支持
- 完成后保留 history/audit 踪迹
这种方法的缺点:
- 需要修改原始脚本
my_script.sh
- 需要清理。
- 使用循环
建议 2:使用 wait
命令和 pgrep
命令
建议了解有关 wait
命令的更多信息 here。
建议了解有关 pgrep
命令的更多信息 here。
my_script.sh "$vid_file" other_args &
wait $(pgrep -f "my_script.sh $vid_file")
这种方法的优点:
- 简单
- 可读
这种方法的缺点:
- 多个用户同时使用相同的命令
wait
命令特定于 Linux bash
可能在其他 shell 中也是如此。检查您当前的支持。
GNU make 具有并行化功能,下面的 Makefile 应该可以与 macOS 附带的非常老的 make 3.81 一起使用。用制表符替换 my_script.sh
之前的 4 个前导空格,并将其存储在名为 Makefile
:
的文件中
.PHONY: all $(VID_FILES)
all: $(VID_FILES)
$(VID_FILES):
my_script.sh "$@" other_args
然后 运行 并行最多 8 个作业:
$ make -j8 VID_FILES="$VID_FILES"
Make 可以做得更好:避免重做已经完成的事情:
TARGETS := $(patsubst %,.%.done,$(VID_FILES))
.PHONY: all clean
all: $(TARGETS)
$(TARGETS): .%.done: %
my_script.sh "$<" other_args
touch "$@"
clean:
rm -f $(TARGETS)
在最后一个版本中,为每个处理过的视频 foo
创建了一个空标签文件 .foo.done
。如果以后你re-run制作和视频foo
没变,就不会re-processed了。键入 make clean
以删除所有标记文件。不要忘记用制表符替换前导空格。
对于 GNU Parallel,它看起来像:
parallel my_script.sh {} other_args ::: $VID_FILES
我想知道如何在 macOS 中等待任何进程完成,因为 wait -n
不起作用。我有一个脚本做几件事,在某些时候它会进入一个循环,调用另一个脚本到后台以利用一些并行性,但不会超过 X 次,因为它效率不高。因此,在创建新进程之前,我需要等待任何子进程完成。
我看过 this question 但它没有回答“任何”部分,它只是说如何等待特定进程完成。
我曾考虑过存储所有 PID 并主动检查它们是否仍然 运行 ps
,但这是非常草率和耗费资源的。我还考虑过将 bash 升级到更新的版本(如果这在 macOS 中是可能的而不破坏 bash 已经工作的方式),但如果没有其他方法可以实际等待 要完成的任何 过程,这是一个非常基本的功能...有什么想法吗?
我的代码的基本版本如下所示:
for vid_file in $VID_FILES
do
my_script.sh $vid_file other_args &
((TOTAL_PROCESSES=TOTAL_PROCESSES+1))
if [ $TOTAL_PROCESSES -ge $MAX_PROCESS ]; then
wait -n
((TOTAL_PROCESSES=TOTAL_PROCESSES-1))
fi
done
我用既不优雅也不高效的方法来替代 wait -n
:
NUM_PROCC=$MAX_PROCESS
while [ $NUM_PROCC -ge $MAX_PROCESS ]
do
sleep 5
NUM_PROCC=$(ps | grep "my_script.sh"| wc -l | tr -d " \t")
# grep command will count as one so we need to remove it
((NUM_PROCC=NUM_PROCC-1))
done
PS:这个问题可以关闭并与我上面提到的问题合并。我刚刚创建了这个新的,因为 Whosebug 不允许我发表评论或提问...
PS2:我明白我的 objective 可以通过其他方式实现。如果您对特定问题本身没有答案,而是有解决方法,请让其他人回答有关“等待任何”的问题,因为它在将来对 me/everyone 也非常有用。我当然会欢迎并感谢解决方法!
提前致谢!
您似乎只想限制同时处于 运行 的进程数。这是使用 bash <= 4.2
:
#!/bin/bash
MAX_PROCESS=2
INPUT_PATH=/somewhere
for vid_file in "$INPUT_PATH"/*
do
while [[ "$(jobs -pr | wc -l)" -ge "$MAX_PROCESS" ]]; do sleep 1; done
my_script.sh "$vid_file" other_args &
done
wait
这是 bash >= 4.3
版本:
#!/bin/bash
MAX_PROCESS=2
INPUT_PATH=/somewhere
for vid_file in "$INPUT_PATH"/*
do
[[ "$(jobs -pr | wc -l)" -ge "$MAX_PROCESS" ]] && wait -n
my_script.sh "$vid_file" other_args &
done
wait
建议 1:完成指标文件
建议将任务完成指示文件添加到您的 my_script.sh
像这样:
echo "[=10=].$(date +%F_%T).done" >> my_script.sh
并在您的部署脚本中测试完成指示器文件是否存在。
rm "my_script.sh.*.done"
my_script.sh "$vid_file" other_args &
while [[ ! -e "my_script.sh.*.done" ]]; do
sleep 5
done
不要忘记清理完成指示器文件。
这种方法的优点:
- 简单
- 所有 shell 都支持
- 完成后保留 history/audit 踪迹
这种方法的缺点:
- 需要修改原始脚本
my_script.sh
- 需要清理。
- 使用循环
建议 2:使用 wait
命令和 pgrep
命令
建议了解有关 wait
命令的更多信息 here。
建议了解有关 pgrep
命令的更多信息 here。
my_script.sh "$vid_file" other_args &
wait $(pgrep -f "my_script.sh $vid_file")
这种方法的优点:
- 简单
- 可读
这种方法的缺点:
- 多个用户同时使用相同的命令
wait
命令特定于 Linuxbash
可能在其他 shell 中也是如此。检查您当前的支持。
GNU make 具有并行化功能,下面的 Makefile 应该可以与 macOS 附带的非常老的 make 3.81 一起使用。用制表符替换 my_script.sh
之前的 4 个前导空格,并将其存储在名为 Makefile
:
.PHONY: all $(VID_FILES)
all: $(VID_FILES)
$(VID_FILES):
my_script.sh "$@" other_args
然后 运行 并行最多 8 个作业:
$ make -j8 VID_FILES="$VID_FILES"
Make 可以做得更好:避免重做已经完成的事情:
TARGETS := $(patsubst %,.%.done,$(VID_FILES))
.PHONY: all clean
all: $(TARGETS)
$(TARGETS): .%.done: %
my_script.sh "$<" other_args
touch "$@"
clean:
rm -f $(TARGETS)
在最后一个版本中,为每个处理过的视频 foo
创建了一个空标签文件 .foo.done
。如果以后你re-run制作和视频foo
没变,就不会re-processed了。键入 make clean
以删除所有标记文件。不要忘记用制表符替换前导空格。
对于 GNU Parallel,它看起来像:
parallel my_script.sh {} other_args ::: $VID_FILES