Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何等待脚本生成的所有子进程(和孙子进程等)_Bash_Shell_Unix_Process - Fatal编程技术网

Bash 如何等待脚本生成的所有子进程(和孙子进程等)

Bash 如何等待脚本生成的所有子进程(和孙子进程等),bash,shell,unix,process,Bash,Shell,Unix,Process,上下文: 用户向我提供自定义脚本以运行。这些脚本可以是任何类型的脚本,类似于启动多个GUI程序、后端服务的脚本。我无法控制脚本的编写方式。这些脚本可以是阻塞类型,即执行等待直到所有子进程(按顺序运行的程序)退出 或非阻塞类型,即在后台分叉子进程并退出类似 #example of non-blocking script echo "START" first_program & second_program & echo "DONE" 我想要实现什么? 用户提供的脚本可以是上述两种

上下文:

用户向我提供自定义脚本以运行。这些脚本可以是任何类型的脚本,类似于启动多个GUI程序、后端服务的脚本。我无法控制脚本的编写方式。这些脚本可以是阻塞类型,即执行等待直到所有子进程(按顺序运行的程序)退出

或非阻塞类型,即在后台分叉子进程并退出类似

#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