[Perl] Problemita
Gunnar Wolf
gwolf en gwolf.org
Mie Abr 19 16:25:55 CDT 2006
Ariel E. Pedrozo - Sysadmin dijo [Wed, Apr 19, 2006 at 06:55:01PM -0300]:
> Hola lista como andan ? tanto tiempo.... tengo un problemita y me gustaria
> saber su opinion...
>
> tengo en uno de mis server linux corriendo sistemas bajo cobol, y hay
> algunos usuarios que quedan con la sesion colgada entonces hay que
> matarlos de forma manual por el PID, para hacerlo mejor hice un pequeño
> script pero nose porque hay veces que funciona y otras veces no.... este
> es el codigo, si me dan una mano bien agradecido estare.
>
> #!/usr/bin/perl
>
> print "Introduzca nombre de usuario :";
> $user = <STDIN>;
>
> system("ps auxw | grep $user | awk '{print $2}' > matar.txt");
>
> open(PID, "< matar.txt");
> @matar =<PID>;
>
> foreach $amatar (@matar){
> system("kill -9 $amatar");
> }
>
> close (PID);
Hola,
Dejando de lado que este problema sólo evidencía que hay problemas que
te _urge_ resolver en tus sistemas Cobol si no quieres tener una
preciosa corrupción de datos o algo por el estilo, hay varios
detallitos a corregir en tu script.
El primero es que te estás complicando a lo bárbaro - Intenta lo
siguiente:
# killall -u usuario
y ya con eso :)
Pero sigo corrigiendo detalles: Si grabas la salida de tu comando en
un archivo de nombre fijo y luego lees ese archivo para limpiar la
tabla de procesos, te abres a una preciosa condición de carrera - ¿Qué
pasa si corres dos instancias del script exactamente a la vez? Bueno,
como tanto system() como open() son llamadas al sistema, es muy
probable que haya un cambio de proceso en ejecución justo en ese
punto, con lo que 'matar.txt' puede variar entre una línea y la
siguiente. Si vas a hacer esto, mejor usa un módulo como File::Temp
para abrir archivos aleatorios. Asómate al manual de File::Temp, viene
con la distribución estándar de Perl.
Ahora, para evitar estar abriendo manualment el archivo, ¿por qué no
capturar directamente los contenidos y re-procesar a patita separando
las líneas, cuando puedes usar las comillas inversas? Substituye por:
@lineas = `ps auxw | grep $user | awk '{print $2}'`;
Mejor aún, Perl está hecho justo para casos como el que describes - Es
más fácil -y mucho más eficiente- hacer esto dentro del mismo Perl que
invocar a dos comandos de shell que lo hagan... Mejor:
@lineas = `ps auxw`;
foreach $amatar @matar {
@data = split /\s*/ $amatar;
# evita que encuentre un proceso que se llame igual que tu
# usuario: Busca sólo en $data[0]
next unless $data[0] eq $user;
system("kill $amatar");
}
Y habrás observado que no le puse 'kill -9', sino simplemente
kill. Puede sonar tentador decirle "muérete, no me importa lo que
pase", pero eso muchas veces te va a dejar el proceso en un triste
estado de descomposición que -nuevamente- te llevará a la corrupción
de datos.
Y si quieres terminar de hacer esto de una manera más limpia y
perlosa (y evitar nuevamente lanzar un comando que necesitas), en vez
de interrogar a través de 'ps auxw' puedes usar un módulo como
Proc::Pid::File o Proc::Process.
Saludos,
--
Gunnar Wolf - gwolf en gwolf.org - (+52-55)5623-0154 / 1451-2244
PGP key 1024D/8BB527AF 2001-10-23
Fingerprint: 0C79 D2D1 2C4E 9CE4 5973 F800 D80E F35A 8BB5 27AF
Más información sobre la lista de distribución Perl