Quiero matar todos los procesos que contienen alguna cadena. Escribí un guión para hacer esto. Sin embargo, cuando lo ejecuto, recibe la señal "Killed" después de la primera iteración del bucle for. Este es mi codigo:

#!/bin/bash

executeCommand () {
 local pname="$1";
 echo $HOSTNAME;
 local  search_terms=($(ps aux | grep $pname | awk '{print $2}'))
 for pros in "${search_terms[@]}";  do
     kill -9 "$pros"
     echo $pros
 done
exit
}

executeCommand "$1"  # get the string that process to be killed contains

Lo ejecuto como ./my_script.sh zookeeper. Cuando elimino la línea que contiene el comando kill, for loop se ejecuta hasta el final; de lo contrario, después del primer comando kill, obtengo como resultado "Killed" y el programa sale.

¿Cuál es la posible razón de esto y cualquier otra solución para alcanzar mi objetivo?

0
Jeyhun Karimov 31 jul. 2016 a las 20:20

2 respuestas

La mejor respuesta

La forma tonta (defectuosa, con errores) de hacer esto es agregar grep -v grep a su canalización:

# ${0##*/} expands to the name of the running script
# ...thus, we avoid killing either grep, or the script itself
ps aux | grep -e "$pname" | egrep -v "grep|${0##*/}" | awk '{print $2}'

La mejor forma es utilizar una herramienta diseñada para el trabajo:

# pkill already, automatically, avoids killing any of its parent processes
pkill "$pname"

Dicho esto, hacer coincidir los procesos por nombre es una mala práctica para empezar; también eliminará less yourproc.log o vim yourproc.conf, no solo yourproc. No lo hagas; en su lugar, utilice un sistema de supervisión de procesos adecuado (advenedizo, herramientas de daemon de DJB, launchd de Apple, systemd, etc.) para monitorear sus demonios de larga ejecución y eliminarlos o reiniciarlos cuando sea necesario.


Por cierto, no hay necesidad de un bucle for en absoluto: kill se pueden pasar múltiples PID en una sola invocación, así:

# a bit longer and bash-specific, but avoids globbing
IFS=$'\n' read -r -d '' -a pids \
  < <(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
      '$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }' \
      && printf '\0')
kill -- "${pids[@]}"

... que también podría formularse como algo como:

# setting IFS and running `set -f` necessary to make unquoted expansion safe
( IFS=$'\n'; set -f; exec kill -- \
  $(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
    '$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }') )
4
Charles Duffy 31 jul. 2016 a las 18:42

Grep mostrará su propio proceso. debe eliminarse usando la opción grep -v

Inténtalo así

for i in ` ps -ef | grep "$pname" | grep -v grep | awk '{print $2}'`
do    
  kill -9 $i
done
-1
sterin jacob 1 ago. 2016 a las 03:32