
El otro día intenté escribir un guión que mataría a unPIDy todos sus procesos secundarios, pero después de dedicarle algún tiempo, decidí que no era confiable, porque a veces algunos de los niños terminaban con unPPIDde1.
Ahora, lo que estoy buscando es cómo puedo ejecutar la siguiente función en segundo plano y tener la función y curl
todo en el mismogrupoy luego elimine este script si se atasca, eliminando todos los elementos secundarios que quedaron en segundo plano:
download(){
until curl -s -S -L -A Mozilla/5.0 -m 300 "$@"; do
echo Retrying in 5 seconds... >&2
sleep 5
done
}
for url in foo.com bar.com baz.com; do
download $url >$url &
done
wait
Sé que no es necesaria esta función download
, pero la incluí aquí porque es una función que uso muchas veces en este script. Además, estoy dando un límite de tiempo máximo de300a curl
, pero dependiendo de algunos errores de red, también se atasca.
Respuesta1
Normalmente, si invoca su script desde un shell interactivo, se colocará en un nuevo grupo de procesos (también conocido como job
), por lo que si está Ctrl-Cen él, todos los procesos iniciados por ese script recibirán un SIGINT.
Si también lo inició en segundo plano (aún desde un shell interactivo), también se iniciará en su propio grupo de procesos.
Puede obtener información sobre grupos de procesos con:
ps -j
( j
es por job control
lo cual es el comportamiento de los shells que ejecutan líneas de comando en grupos de procesos para poder administrarlos (primer plano/fondo/eliminar/suspender/reanudar)).
Puedes informarte sobre eltrabajosde su shell interactivo con el jobs
comando (aunque no todos los procesos que contiene). jobs -p
le mostrará la identificación del grupo de procesos.
Puede eliminar a los miembros de un grupo de procesos enviando una señal a -x
dónde x
está la identificación del grupo de procesos (PGID) o utilizando especificaciones de trabajos con %job-number
. Por ejemplo:
$ sleep 30 | sleep 40 &
[1] 6950 6951
$ ps -j
PID PGID SID TTY TIME CMD
6031 6031 6031 pts/3 00:00:00 zsh
6950 6950 6031 pts/3 00:00:00 sleep
6951 6950 6031 pts/3 00:00:00 sleep
6952 6952 6031 pts/3 00:00:00 ps
$ kill -- -6950
[1] + terminated sleep 30 | sleep 40
$ sleep 30 | sleep 40 &
[1] 6955 6957
$ jobs
[1] + running sleep 30 | sleep 40
$ kill %1
[1] + terminated sleep 30 | sleep 40
Ahora, si no se inicia desde un shell interactivo, su script terminará en el mismo grupo de procesos que su padre. Entonces, matar ese grupo de procesos podría terminar matando muchos otros procesos que no deseas matar.
Lo que podría hacer en su script es iniciar el grupo de procesos usted mismo.
Me gusta agregando:
[ "$(ps -o pgid= -p "$$")" -eq "$$" ] ||
exec perl -e 'setpgrp or die "setpgrp; $!"; exec @ARGV' -- "$0" "$@"
(que vuelve a ejecutar el script después de haber llamado perl
para iniciar un nuevo grupo de procesos si detectamos que no somos un líder de grupo de procesos) al inicio de su script.
De esa manera, tiene la garantía de que el script se ejecutará en su propio grupo de procesos.
Sin embargo, lo que eso significa es que si lo haces:
something | myscript | something
En un shell interactivo, es probable que myscript
no sea el líder del grupo de proceso. Al hacer lo setpgrp
anterior, el script ya no estará en el grupo de procesos de primer plano de la terminal, lo que significa Ctrl-Cque no lo eliminará.