在退出脚本之前等待后台进程完成

在退出我的脚本(TCL / Bash)之前,如何确保所有的后台进程都已经完成了执行。

我正在考虑将所有的后台进程pid写入一个pid文件。 然后在结束pgrep pidfile,看看有没有进程在我退出前还在运行。

有没有更简单的方法来做到这一点? 有没有一个TCL具体的方式来做到这一点?

如果你想等待工作完成,请使用wait 。 这将使shell等待所有后台作业完成。 然而,如果你的任何工作都是守护进程的,那么他们就不再是shell的孩子了,等待也不会有任何效果(就shell而言,这个孩子已经完成了)的确如此,当一个进程被守护进程的时候,通过终止和产生一个inheritance它的angular色的新进程)。

 #!/bin/sh { sleep 5; echo waking up after 5 seconds; } & { sleep 1; echo waking up after 1 second; } & wait echo all jobs are done! 

您可以使用kill -0来检查特定的pid是否正在运行。

假设你有一个名为pid文件中的pid号码列表

 while true; do if [ -s pid ] ; then for pid in `cat pid` do echo "Checking the $pid" kill -0 "$pid" 2>/dev/null || sed -i "/^$pid$/d" pid done else echo "All your process completed" ## Do what you want here... here all your pids are in finished stated break fi done 

警告 :长脚本提前。

前一段时间,我遇到了一个类似的问题:从一个Tcl脚本,启动一些进程,然后等待所有这些完成。 这是我写的一个演示脚本来解决这个问题。

main.tcl

 #!/usr/bin/env tclsh # Launches many processes and wait for them to finish. # This script will works on systems that has the ps command such as # BSD, Linux, and OS X package require Tclx; # For process-management utilities proc updatePidList {stat} { global pidList global allFinished # Parse the process ID of the just-finished process lassign $stat processId howProcessEnded exitCode # Remove this process ID from the list of process IDs set pidList [lindex [intersect3 $pidList $processId] 0] set processCount [llength $pidList] # Occasionally, a child process quits but the signal was lost. This # block of code will go through the list of remaining process IDs # and remove those that has finished set updatedPidList {} foreach pid $pidList { if {![catch {exec ps $pid} errmsg]} { lappend updatedPidList $pid } } set pidList $updatedPidList # Show the remaining processes if {$processCount > 0} { puts "Waiting for [llength $pidList] processes" } else { set allFinished 1 puts "All finished" } } # A signal handler that gets called when a child process finished. # This handler needs to exit quickly, so it delegates the real works to # the proc updatePidList proc childTerminated {} { # Restart the handler signal -restart trap SIGCHLD childTerminated # Update the list of process IDs while {![catch {wait -nohang} stat] && $stat ne {}} { after idle [list updatePidList $stat] } } # # Main starts here # puts "Main begins" set NUMBER_OF_PROCESSES_TO_LAUNCH 10 set pidList {} set allFinished 0 # When a child process exits, call proc childTerminated signal -restart trap SIGCHLD childTerminated # Spawn many processes for {set i 0} {$i < $NUMBER_OF_PROCESSES_TO_LAUNCH} {incr i} { set childId [exec tclsh child.tcl $i &] puts "child #$i, pid=$childId" lappend pidList $childId after 1000 } # Do some processing puts "list of processes: $pidList" puts "Waiting for child processes to finish" # Do some more processing if required # After all done, wait for all to finish before exiting vwait allFinished puts "Main ends" 

child.tcl

 #!/usr/bin/env tclsh # child script: simulate some lengthy operations proc randomInteger {min max} { return [expr int(rand() * ($max - $min + 1) * 1000 + $min)] } set duration [randomInteger 10 30] puts " child #$argv runs for $duration miliseconds" after $duration puts " child #$argv ends" 

运行main.tcl的输出示例

 Main begins child #0, pid=64525 child #0 runs for 17466 miliseconds child #1, pid=64526 child #1 runs for 14181 miliseconds child #2, pid=64527 child #2 runs for 10856 miliseconds child #3, pid=64528 child #3 runs for 7464 miliseconds child #4, pid=64529 child #4 runs for 4034 miliseconds child #5, pid=64531 child #5 runs for 1068 miliseconds child #6, pid=64532 child #6 runs for 18571 miliseconds child #5 ends child #7, pid=64534 child #7 runs for 15374 miliseconds child #8, pid=64535 child #8 runs for 11996 miliseconds child #4 ends child #9, pid=64536 child #9 runs for 8694 miliseconds list of processes: 64525 64526 64527 64528 64529 64531 64532 64534 64535 64536 Waiting for child processes to finish Waiting for 8 processes Waiting for 8 processes child #3 ends Waiting for 7 processes child #2 ends Waiting for 6 processes child #1 ends Waiting for 5 processes child #0 ends Waiting for 4 processes child #9 ends Waiting for 3 processes child #8 ends Waiting for 2 processes child #7 ends Waiting for 1 processes child #6 ends All finished Main ends 

GNU parallelxargs是可以简化脚本的两个工具,也可以控制最大线程数(线程池)。 例如:

 seq 10 | xargs -P4 -I'{}' echo '{}' 

要么:

 seq 10 | parallel -j4 echo '{}' 

另请参见: 如何编写进程池bash shell