Question

J'ai un problème avec certains processus de type zombie sur un certain serveur qui doivent être supprimés de temps en temps.Comment puis-je identifier au mieux ceux qui ont duré plus d’une heure environ ?

Était-ce utile?

La solution

S'ils ont juste besoin d'être tués :

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi

Si tu veux voir à quoi ça correspond

if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi

Le -i flag vous demandera oui/non pour chaque correspondance de processus.

Autres conseils

J'ai trouvé une réponse qui fonctionne pour moi :

avertissement:cela trouvera et tuer processus de longue durée

ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}

(Où ID de l'utilisateur est l'ID d'un utilisateur spécifique avec des processus de longue durée.)

La deuxième expression régulière correspond à une heure comportant un chiffre de jours facultatif, suivi d'un composant heure, minute et seconde, et dure donc au moins une heure.

Pour tout ce qui date de plus d'un jour,

ps aux

vous donnera la réponse, mais elle se résume à une précision journalière, ce qui pourrait ne pas être aussi utile.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   7200   308 ?        Ss   Jun22   0:02 init [5]
root         2  0.0  0.0      0     0 ?        S    Jun22   0:02 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Jun22   0:18 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Jun22   0:00 [watchdog/0]

Si vous êtes sous Linux ou un autre système avec le système de fichiers /proc, dans cet exemple, vous pouvez voir uniquement que le processus 1 est en cours d'exécution depuis le 22 juin, mais aucune indication sur l'heure à laquelle il a été démarré.

stat /proc/<pid>

vous donnera une réponse plus précise.Par exemple, voici un horodatage exact pour le processus 1, que ps affiche uniquement sous la forme Jun22 :

ohm ~$ stat /proc/1
  File: `/proc/1'
  Size: 0               Blocks: 0          IO Block: 4096   directory
Device: 3h/3d   Inode: 65538       Links: 5
Access: (0555/dr-xr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2008-06-22 15:37:44.347627750 -0700
Modify: 2008-06-22 15:37:44.347627750 -0700
Change: 2008-06-22 15:37:44.347627750 -0700

De cette façon, vous pouvez obtenir la liste des dix processus les plus anciens :

ps -elf | sort -r -k12 | head -n 10

Jodie C et d'autres ont souligné que killall -i peut être utilisé, ce qui est très bien si vous souhaitez utiliser le nom du processus pour tuer.Mais si vous voulez tuer selon les mêmes paramètres que pgrep -f, vous devez utiliser quelque chose comme ce qui suit, en utilisant pure bash et le /proc système de fichiers.

#!/bin/sh                                                                                                                                               

max_age=120 # (seconds)                                                                                                                                 
naughty="$(pgrep -f offlineimap)"                                                                                                                       
if [[ -n "$naughty" ]]; then # naughty is running                                                                                                       
  age_in_seconds=$(echo "$(date +%s) - $(stat -c %X /proc/$naughty)" | bc)                                                                              
  if [[ "$age_in_seconds" -ge "$max_age" ]]; then # naughty is too old!                                                                                 
    kill -s 9 "$naughty"                                                                                                                                
  fi                                                                                                                                                    
fi     

Cela vous permet de trouver et de tuer des processus plus anciens que max_age secondes en utilisant le nom complet du processus;c'est-à-dire le processus nommé /usr/bin/python2 offlineimap peut être tué en faisant référence à "offlineimap", alors que le killall les solutions présentées ici ne fonctionneront que sur la chaîne « python2 ».

Proc::ProcessTable de Perl fera l'affaire :http://search.cpan.org/dist/Proc-ProcessTable/

Vous pouvez l'installer sur Debian ou Ubuntu avec sudo apt-get install libproc-processtable-perl

Voici un one-liner :

perl -MProc::ProcessTable -Mstrict -w -e 'my $anHourAgo = time-60*60; my $t = new Proc::ProcessTable;foreach my $p ( @{$t->table} ) { if ($p->start() < $anHourAgo) { print $p->pid, "\n" } }'

Ou, plus formaté, mettez ceci dans un fichier appelé process.pl :

#!/usr/bin/perl -w
use strict;
use Proc::ProcessTable;
my $anHourAgo = time-60*60;
my $t = new Proc::ProcessTable;
foreach my $p ( @{$t->table} ) {
    if ($p->start() < $anHourAgo) {
        print $p->pid, "\n";
    }
}

puis cours perl process.pl

Cela vous donne plus de polyvalence et une résolution d'une seconde sur l'heure de démarrage.

Vous pouvez utiliser bc pour joindre les deux commandes dans la réponse de mob et obtenir le nombre de secondes écoulées depuis le démarrage du processus :

echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc

modifier:

Par ennui en attendant que de longs processus s'exécutent, voici ce qui est ressorti après quelques minutes de bidouillage :

#file: sincetime
#!/bin/bash
init=`stat -t /proc/$1 | awk '{print $14}'`
curr=`date +%s`
seconds=`echo $curr - $init| bc`
name=`cat /proc/$1/cmdline`
echo $name $seconds

Si vous mettez ceci sur votre chemin et l'appelez comme ceci :depuis toujours

il imprimera la ligne de commande du processus et les secondes depuis le démarrage.Vous pouvez également mettre ceci sur votre chemin :

#file: greptime
#!/bin/bash
pidlist=`ps ax | grep -i -E $1 | grep -v grep | awk '{print $1}' | grep -v PID | xargs echo`
for pid in $pidlist; do
    sincetime $pid
done

Et que si vous exécutez :

greptime <pattern>

où patterns est une chaîne ou une expression régulière étendue, il affichera tous les processus correspondant à ce modèle et les secondes depuis leur démarrage.:)

fait une ps -aef.cela vous montrera l'heure à laquelle le processus a commencé.Puis en utilisant le date commande trouver l’heure actuelle.Calculez la différence entre les deux pour trouver l’âge du processus.

J'ai fait quelque chose de similaire à la réponse acceptée mais légèrement différemment puisque je souhaite faire une correspondance en fonction du nom du processus et en fonction du mauvais processus exécuté pendant plus de 100 secondes.

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')

stat -t /proc/<pid> | awk '{print $14}'

pour obtenir l'heure de début du processus en secondes depuis l'époque.Comparez avec l'heure actuelle (date +%s) pour obtenir l'âge actuel du processus.

Utiliser ps est la bonne façon.J'ai déjà fait quelque chose de similaire auparavant, mais je n'ai pas la source sous la main.Généralement, ps a la possibilité de lui indiquer les champs à afficher et par lesquels trier.Vous pouvez trier la sortie par durée d'exécution, saisir le processus souhaité, puis le supprimer.

HTH

Si quelqu'un en a besoin en C, vous pouvez utiliser readproc.h et libproc :

#include <proc/readproc.h>
#include <proc/sysinfo.h>

float
pid_age(pid_t pid)
{
        proc_t proc_info;
        int seconds_since_boot = uptime(0,0);
        if (!get_proc_stats(pid, &proc_info)) {
                return 0.0;
        }

        // readproc.h comment lies about what proc_t.start_time is. It's
        // actually expressed in Hertz ticks since boot

        int  seconds_since_1970 = time(NULL);
        int time_of_boot = seconds_since_1970 - seconds_since_boot;
        long  t = seconds_since_boot - (unsigned long)(proc_info.start_time / Hertz);

        int delta = t;
        float days = ((float) delta / (float)(60*60*24));
        return days;
}

Je suis tombé quelque part... j'ai trouvé que c'était simple et utile

Vous pouvez utiliser la commande directement dans crontab,

* * * * * ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);'

ou, nous pouvons l'écrire sous forme de script shell,

#!/bin/sh
# longprockill.sh
ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F[13]; kill
+ 9, $F[3] if ($h > 1);'

Et appelle-le crontab comme ça,

* * * * * longprockill.sh

Ma version de sincetime ci-dessus par @Rafael S.Calsaverini :

#!/bin/bash
ps --no-headers -o etimes,args "$1"

Cela inverse les champs de sortie :le temps écoulé en premier, la commande complète incluant les arguments en second.Ceci est préférable car la commande complète peut contenir des espaces.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top