Mata todos los trabajos en segundo plano

63

¿Existe una forma más compacta de matar trabajos en segundo plano que:

for i in {1..5}; do kill %$i; done

Además, {1..5} obviamente tiene un número mágico codificado, ¿cómo puedo hacer que sea "N" con N siendo el número correcto, sin hacer un:

$(jobs | wc -l)

De hecho, uso \ j en PS1 para obtener el número de trabajos administrados, ¿es esto equivalente?

Robottinosino
fuente
3
kill $(jobs -p)Parece más fácil
jw013
Preferiría matar trabajos individualmente, si es posible. (Aunque podría haber entendido mal su comentario)
Robottinosino
for pid in $(jobs -p); do kill $pid; done?
jw013
3
@ jw013 No solo es más fácil, en realidad es correcto (publíquelo como respuesta), a diferencia de una solución basada en contar las líneas de la salida de las jobscuales solo funciona si los trabajos se numeran consecutivamente. Ah, y "matar trabajos individualmente" no tiene sentido: pasar varios PID al killcomando hace exactamente lo mismo que pasarlos por separado.
Gilles 'SO- deja de ser malvado'
Estaba ingresando el comando incorrectamente, eliminé las palabras $ (jobs -p) y también me parece muy correcto. Listo para aceptar
Robottinosino

Respuestas:

101

Para killtodos los trabajos en segundo plano gestionados por bash, haga

kill $(jobs -p)

Tenga en cuenta que dado que ambos jobsy killestán incorporados en bash, no se debe ejecutar en cualquier otro error de la lista de argumentos demasiado larga tipo.

jw013
fuente
2
También para la posteridad, lo que piensa bahamat es la forma de hacerlo, zshdescalificándolos como cualquier autoridad sobre el tema.
Peth
Siento que debería saber esto, pero ¿cómo funciona el '$' aquí?
fersarr
1
@fersarr Aquí tienes
jw013
@bahamat Eso no funciona realmente ya que el PID puede estar en el campo 2 o 3 dependiendo de si el trabajo es uno de% + o% - o no. Lo que funciona es kill %${(k)^jobdirs}, que de hecho es más largo; si necesita enumerar los PID, puede usarlos por más tiempo ${${jobstates#*:*:}%%=*}.
Gilles 'SO- deja de ser malvado'
En CentOS, mi mensaje espera más información>
Janac Meena
15

Use en xargslugar del $(jobs -p)subcomando, porque si jobs -pestá vacío, el comando kill fallará.

jobs -p | xargs kill
brunocascio
fuente
1
Sin embargo, esto tiene el mismo efecto exacto, imprime la ayuda y sale con el código 123
cat
1
El comando funciona bien en OSX pero no funciona en Debian
brunocascio
Esto funciona muy bien en CentOS 6
Janac Meena
jobs -p | xargs -rn10 killfuncionará mejor si jobs -pno devuelve ningún PID. Tenga en cuenta que la -ropción es la extensión GNU.
NarūnasK
Como se mencionó anteriormente, -res el formato corto para la --no-run-if-emptyextensión GNU xargsque le indica que no ejecute el comando si stdin no tiene datos.
Anthony G - justicia para Monica
3

Prefiero verificar si hay trabajos que existan antes de eliminarlos, de esta manera el script no fallará si no hay nada en ejecución.

También es más corto de escribir. Lanza esto en tu .bash_profile:

function killjobs () {
    JOBS="$(jobs -p)";
    if [ -n "${JOBS}" ]; then;
        kill -KILL ${JOBS};
    fi
}

Entonces corre:

killjobs

Para matar cualquier trabajo en ejecución.

mikemaccana
fuente
1

Tengo varios comandos compuestos en segundo plano que quiero terminar con gracia, enviando SIGINT a cada proceso, en macOS. Ninguna de las otras soluciones funcionó correctamente para eso, así que se me ocurrió esto:

jobs -p | xargs -n1 pkill -SIGINT -g

jobs -p enumera los procesos en segundo plano iniciados por el shell actual.

xargs -n1 ejecuta pkill una vez para cada trabajo.

pkill -SIGINT -g envía SIGINT (igual que ctrl + c) a todos los procesos en el grupo de procesos.

Clement Cherlin
fuente
1

Supongo que dependiendo de lo que jobs -pdé la salida , la solución podría ser ligeramente diferente. En mi caso

$ jobs -p
[1]  - 96029 running    some job
[2]  + 96111 running    some other job

Por lo tanto, hacer lo siguiente no es bueno.

$ jobs -p | xargs kill
kill: illegal process id: [1]

Por otro lado, la ejecución kill $(jobs -p)sí funciona pero conlleva muchos mensajes de error, ya que las cadenas que no son PID también se pasan kill.

Por lo tanto, mi solución es grepprimero el PID y luego usarlo de la xargssiguiente manera:

$ jobs -p | grep -o -E '\s\d+\s' | xargs kill
Fanchen Bao
fuente
1
¿Qué caparazón estás usando? ¿Qué echo $0muestra? ¿Qué help jobsmuestra? La salida ilustrada no es compatible con POSIX ; cualquier implementación de jobsdebería tener una -popción con el comportamiento deseado.
Comodín el
1
Gracias por señalar esto. Estoy usando zsh, y esa es la razón de la extraña salida. Cambié a bash y jobs -psolo hice salir PID. Acabo de enterarme de que zsh no es completamente compatible con POSIX.
Fanchen Bao
0

Parece que jobs -p | xargs killhace el trabajo, sin embargo, produce una salida no deseada canalizada para matar. Aquí estoy agrupando la salida de jobs -ptener / no tener + o - carácter

function killjobs() {
    JOBS=$(jobs -p)
    echo $JOBS | grep -v "+\|-"| awk '{print $2}' | xargs kill -9
    echo $JOBS | grep "+\|-"| awk '{print $3}' | xargs kill -9
}

Y luego puedes llamar killjobs

samvel1024
fuente