versiones guia espaƱol descargar actualizar bash shell unix tcl grep

bash - guia - qgis manual



En espera de que finalicen los procesos en segundo plano antes de salir del script (4)

Puede usar kill -0 para verificar si un pid en particular se está ejecutando o no.

Asumiendo, usted tiene una lista de números pid en un archivo llamado pid en pwd

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

¿Cómo me aseguro de que todos los procesos en segundo plano hayan finalizado la ejecución antes de salir de mi script (TCL / Bash)?

Estaba pensando en escribir todos mis procesos de fondo para un archivo pid. Y luego, al final, pgrep el archivo pid para ver si todavía hay algún proceso ejecutándose antes de salir.

¿Hay alguna manera más simple de hacer esto? ¿Y hay una forma específica de TCL para hacer esto?


Si quiere esperar a que terminen los trabajos, use wait . Esto hará que el shell espere hasta que se completen todos los trabajos en segundo plano. Sin embargo, si alguno de sus trabajos se demoniza a sí mismos, ya no son hijos del intérprete de órdenes y esperar no tendrá ningún efecto (en lo que respecta al shell, el niño ya está hecho. De hecho, cuando un proceso se demoniza a sí mismo, lo hace terminando y generando un nuevo proceso que hereda su función).

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


ADVERTENCIA : larga secuencia de comandos por delante.

Hace un tiempo, me enfrenté a un problema similar: desde un script Tcl, inicie varios procesos y luego espere a que todos terminen. Aquí hay un script de demostración que escribí para resolver este problema.

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"

Ejemplo de salida para ejecutar 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 parallel y xargs son dos herramientas que pueden simplificar los scripts y también controlar el número máximo de subprocesos (grupo de subprocesos). P.ej:

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

o:

seq 10 | parallel -j4 echo ''{}''

Vea también: cómo escribir un shell de bash de pool de proceso