Bash 如何等待脚本生成的所有子进程(和孙子进程等)
上下文: 用户向我提供自定义脚本以运行。这些脚本可以是任何类型的脚本,类似于启动多个GUI程序、后端服务的脚本。我无法控制脚本的编写方式。这些脚本可以是阻塞类型,即执行等待直到所有子进程(按顺序运行的程序)退出 或非阻塞类型,即在后台分叉子进程并退出类似Bash 如何等待脚本生成的所有子进程(和孙子进程等),bash,shell,unix,process,Bash,Shell,Unix,Process,上下文: 用户向我提供自定义脚本以运行。这些脚本可以是任何类型的脚本,类似于启动多个GUI程序、后端服务的脚本。我无法控制脚本的编写方式。这些脚本可以是阻塞类型,即执行等待直到所有子进程(按顺序运行的程序)退出 或非阻塞类型,即在后台分叉子进程并退出类似 #example of non-blocking script echo "START" first_program & second_program & echo "DONE" 我想要实现什么? 用户提供的脚本可以是上述两种
#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"
我想要实现什么?
用户提供的脚本可以是上述两种类型中的任意一种,也可以是两者的混合。我的工作是运行脚本并等待它启动的所有进程退出,然后关闭节点。如果它是阻塞类型,则case非常简单,即获取脚本执行过程的PID,并等待ps-ef | grep-ef PID没有更多条目。非阻塞脚本给我带来了麻烦
是否有一种方法可以获取通过执行脚本生成的所有子进程的PID列表?任何指针或提示都将受到高度赞赏
ps--ppid$PID
将使用$PID
列出进程的所有子进程ps--ppid$PID
将使用$PID列出进程的所有子进程。您可以打开一个由其他进程继承的文件描述符,然后等到它不再使用。这是一种低开销的方法,通常可以很好地工作,但如果流程需要,也可以绕过它:
foo=$(mktemp)
( flock -x 5000; theirscript; ) 5000> "$foo"
flock -x 0 < "$foo"
rm "$foo"
echo "The script and its subprocesses are done"
您可以打开由其他进程继承的文件描述符,然后等待它不再使用。这是一种低开销的方法,通常可以很好地工作,但如果流程需要,也可以绕过它:
foo=$(mktemp)
( flock -x 5000; theirscript; ) 5000> "$foo"
flock -x 0 < "$foo"
rm "$foo"
echo "The script and its subprocesses are done"
您可以使用pgrep-p
获取子进程的列表。例如:
IFS=$'\n' read -ra CHILD_PROCS -d '' < <(exec pgrep -P "$1")
IFS=$'\n'read-ra CHILD\u PROCS-d'<您可以使用pgrep-p
获取子进程列表。例如:
IFS=$'\n' read -ra CHILD_PROCS -d '' < <(exec pgrep -P "$1")
IFS=$'\n“read-ra CHILD\u PROCS-d”<您可以使用wait
等待userscript
启动的所有后台进程完成。由于wait
仅适用于当前shell的子脚本,因此您需要为它们的脚本编写源代码,而不是将其作为单独的进程运行
( source userscript; wait )
在显式子shell中寻找脚本应该足够紧密地模拟启动新流程。如果没有,您还可以将子shell设置为后台,强制启动一个新进程,然后等待它完成
( source userscript; wait ) & wait
您可以使用wait
等待userscript
启动的所有后台进程完成。由于wait
仅适用于当前shell的子脚本,因此您需要为它们的脚本编写源代码,而不是将其作为单独的进程运行
( source userscript; wait )
在显式子shell中寻找脚本应该足够紧密地模拟启动新流程。如果没有,您还可以将子shell设置为后台,强制启动一个新进程,然后等待它完成
( source userscript; wait ) & wait
简单地回答被问到的问题。您可以将要调用的每个脚本的进程ID存储到同一个变量中:
echo "START"
first_program &
child_process_ids+="$! "
second_program &
child_process_ids+="$! "
echo $child_process_ids
echo "DONE"
$child\u process\u id只是一个以空格分隔的进程id字符串。现在,这回答了我的问题,但是,我会做的有点不同。我将从for循环调用每个脚本,存储其进程ID,然后在另一个for循环中等待每个脚本完成,并分别检查每个退出代码。使用相同的示例,下面是它的外观
echo "START"
scripts="first_program second_program"
for script in $scripts; do
#Call script and send to background
./$script &
#Store the script's processID that was just sent to the background
child_process_ids+="$! "
done
for child_process_id in $child_process_ids; do
#Pass each processId into the wait command to retrieve its exit
#code and store it in $rc
wait $child_process_id
rc=$?
#Inspect each processes exit code
if [ $rc -ne 0 ]; then
echo "$child_process_id failed with an exit code of $rc"
else
echo "$child_process_id was successful"
fi
done
简单地回答被问到的问题。您可以将要调用的每个脚本的进程ID存储到同一个变量中:
echo "START"
first_program &
child_process_ids+="$! "
second_program &
child_process_ids+="$! "
echo $child_process_ids
echo "DONE"
$child\u process\u id只是一个以空格分隔的进程id字符串。现在,这回答了我的问题,但是,我会做的有点不同。我将从for循环调用每个脚本,存储其进程ID,然后在另一个for循环中等待每个脚本完成,并分别检查每个退出代码。使用相同的示例,下面是它的外观
echo "START"
scripts="first_program second_program"
for script in $scripts; do
#Call script and send to background
./$script &
#Store the script's processID that was just sent to the background
child_process_ids+="$! "
done
for child_process_id in $child_process_ids; do
#Pass each processId into the wait command to retrieve its exit
#code and store it in $rc
wait $child_process_id
rc=$?
#Inspect each processes exit code
if [ $rc -ne 0 ]; then
echo "$child_process_id failed with an exit code of $rc"
else
echo "$child_process_id was successful"
fi
done
如果我是你的话,我会在启动子进程时传递一个唯一的参数,你可以稍后对其进行grep,子进程将忽略该参数。@user814064谢谢您的回复,但我无法控制脚本的编写方式如果我是您,我只会在启动子进程时传递一个唯一的参数,您可以稍后重试,子进程将忽略该问题。@user814064谢谢您的回复,但我无法控制脚本的编写方式主脚本一退出(以微秒为单位,因为它只需要在后台启动两个进程),子进程将作为父进程分配给INIT。没有?是的。如果父进程要退出,则需要在退出之前创建子进程列表,例如在文件中。一旦主脚本退出(以微秒为单位,因为它只需要在后台启动两个进程),子进程将作为父进程分配给INIT。没有?是的。如果父项要退出,您需要在退出之前创建子PID列表,例如在文件中。像charm一样工作-谢谢@chepnerIn在第二个片段中,您真的需要子shell吗?{source userscript;wait;}&wait
不够吗?(&
背景组…)命令组可能会很好。我不记得在第一个片段的背景之外,我花了太多的心思。工作得很有魅力-谢谢@chepnerIn第二个片段,你真的需要一个subshell吗?{source userscript;wait;}&wait
不够吗?(&
背景组…)命令组可能会很好。我不记得除了给第一个代码片段添加背景之外,我花了太多心思。如果你能在这个答案中添加相关的代码片段(如果你有权这么做的话),那会很有帮助。@sideshowbarker好的,我做了一个upda