等待MacOS上的任何儿童进程退出?

发布于 2025-01-20 09:25:23 字数 1269 浏览 6 评论 0原文

我想知道如何在 macOS 中等待任何进程完成,因为 wait -n 不起作用。我有一个脚本在做几件事,在某些时候它会进入一个循环,在后台调用另一个脚本来利用一些并行性,但不会超过 X 次,因为它效率不高。因此,我需要等待任何子进程完成才能创建新进程。

我见过这个问题,但它没有不回答“任何”部分,它只是说明如何等待特定进程完成。

我曾考虑过存储所有 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:这个问题可以关闭并与我上面提到的问题合并。我刚刚创建了这个新的,因为 stackoverflow 不允许我发表评论或询问...

PS2:我确实明白我的目标可以通过其他方式实现。如果您没有特定问题本身的答案,而是有解决方法,请让其他人回答有关“等待任何”的问题,因为这对我/每个人将来也非常有用。我当然也会欢迎并感谢您的解决方法!

先感谢您!

I am wondering how to wait for any process to finish in macOS, since wait -n doesn't work. I have a script doing several things, and in some point it will enter a loop calling another script to the background to exploit some parallelism, but not more than X times since it wouldn't be efficient. Thus, I need to wait for any child process to finish before creating new processes.

I have seen this question but it doesn't answer the "any" part, it just says how to wait to a specific process to finish.

I've thought of either storing all PIDs and actively checking if they're still running with ps, but it's very slapdash and resource consuming. I also thought about upgrading bash to a newer version (if that's ever possible in macOS without breaking how bash already works), but I would be very disappointed if there was no other way to actually wait for any process to finish, it's such a basic feature... Any ideas?

A basic version of my code would look like this:

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

My neither elegant nor performant approach to substitute the 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: This question could be closed and merged with the one I mentioned above. I've just created this new one because stackoverflow wouldn't let me comment or ask...

PS2: I do understand that my objective could be achieved by other means. If you don't have an answer for the specific question itself but rather a workaround, please let other people answer the question about "waiting any" since it would be very useful for me/everyone in the future as well. I will of course welcome and be thankful for the workaround too!

Thank you in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

电影里的梦 2025-01-27 09:25:23

看起来您只是想限制同时运行的进程数量。这是使用 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

It seems like you just want to limit the number of processes that are running at the same time. Here's a rudimentary way to do it with 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

Here's the bash >= 4.3 version:

#!/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
若有似无的小暗淡 2025-01-27 09:25:23

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 "
lt;" other_args
    touch "$@"

clean:
    rm -f $(TARGETS)

在最后一个版本中,会为每个处理的视频 foo 创建一个空标记文件 .foo.done。如果稍后您重新运行 make 并且视频 foo 没有改变,则不会重新处理。输入 make clean 以删除所有标记文件。不要忘记用制表符替换前导空格。

GNU make has parallelization capabilities and the following Makefile should work even with the very old make 3.81 that comes with macOS. Replace the 4 leading spaces before my_script.sh by a tab and store this in a file named Makefile:

.PHONY: all $(VID_FILES)
all: $(VID_FILES)

$(VID_FILES):
    my_script.sh "$@" other_args

And then to run 8 jobs max in parallel:

$ make -j8 VID_FILES="$VID_FILES"

Make can do even better: avoid redoing things that have already been done:

TARGETS := $(patsubst %,.%.done,$(VID_FILES))
.PHONY: all clean
all: $(TARGETS)

$(TARGETS): .%.done: %
    my_script.sh "
lt;" other_args
    touch "$@"

clean:
    rm -f $(TARGETS)

With this last version an empty tag file .foo.done is created for each processed video foo. If, later, you re-run make and video foo did not change, it will not be re-processed. Type make clean to delete all tag files. Do not forget to replace the leading spaces by a tab.

北陌 2025-01-27 09:25:23

建议 1:完成指示文件

建议将任务完成指示文件添加到您的 my_script.sh 中,

如下所示:

 echo "$0.$(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

不要忘记清理完成指示器文件。

此方法的优点:

  1. 简单
  2. 在所有 shell 中均受支持
  3. 完成时保留历史记录/审核跟踪

此方法的缺点:

  1. 需要修改原始脚本 my_script.sh
  2. 需要清理。
  3. 使用循环

建议2:将wait命令与pgrep命令结合使用

建议详细了解wait命令此处

建议在此处了解有关 pgrep 命令的更多信息。

my_script.sh "$vid_file" other_args &     
wait $(pgrep -f "my_script.sh $vid_file")

这种方法的优点:

  1. 简单
  2. 易读

这种方法的缺点:

  1. 多个用户同时使用同一命令
  2. wait 命令是特定于 Linux bash 的,也许在其他 shell 中也是如此。检查您当前的支持。

Suggestion 1: Completion indicator file

Suggesting to add task completion indication file to your my_script.sh

Like this:

 echo "$0.$(date +%F_%T).done" >> my_script.sh

And in your deployment script test if the completion indicator file exist.

rm "my_script.sh.*.done"
my_script.sh "$vid_file" other_args &     
while [[ ! -e "my_script.sh.*.done" ]]; do
    sleep 5
done

Don't forget to clean up the completion indicator files.

Advantages for this approach:

  1. Simple
  2. Supported in all shells
  3. Retain a history/audit trail on completion

Disadvantages for this approach:

  1. Requires modification to original script my_script.sh
  2. Requires cleanup.
  3. Using loop

Suggestion 2: Using wait command with pgrep command

Suggesting to learn more about wait command here.

Suggesting to learn more about pgrep command here.

my_script.sh "$vid_file" other_args &     
wait $(pgrep -f "my_script.sh $vid_file")

Advantages for this approach:

  1. Simple
  2. Readable

Disadvantages for this approach:

  1. Multiple users using same command same time
  2. wait command is specific to Linux bash maybe in other shells as well. Check your current support.
奈何桥上唱咆哮 2025-01-27 09:25:23

使用GNU平行,它看起来像:

parallel my_script.sh {} other_args ::: $VID_FILES

With GNU Parallel it would look something like:

parallel my_script.sh {} other_args ::: $VID_FILES
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文