Comment puis-je tuer les processus plus anciens que «t»?

14

Tout d'abord, oui, j'ai vu cette question:

Trouver (et tuer) d'anciens processus

Les réponses sont incorrectes et ne fonctionnent pas. J'ai voté et commenté en conséquence.

Les processus que je veux tuer ressemblent à ceci lorsqu'ils sont répertoriés avec ps aux | grep page.py:

apache 424 0,0 0,1 6996 4564? S 07:02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2686 0,0 0,1 7000 3460? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2926 0,0 0,0 6996 1404? S Sep02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 7398 0,0 0,0 6996 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 9423 0,0 0,1 6996 3824? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 11022 0,0 0,0 7004 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15343 0,0 0,1 7004 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15364 0,0 0,1 7004 3792? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15397 0,0 0,1 6996 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 16817 0,0 0,1 7000 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 17590 0,0 0,0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 24448 0,0 0,0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 30361 0,0 0,1 6996 3776? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py

Je cherche à configurer un simple cron quotidien qui trouvera et tuera tous les page.pyprocessus de plus d'une heure.

La réponse acceptée à la question susmentionnée ne fonctionne pas, car elle ne correspond pas à une plage de temps, elle correspond simplement à des processus qui ont fonctionné de 7 jours à 7 jours 23 heures 59 minutes et 59 secondes. Je ne veux pas tuer les processus qui ont fonctionné depuis 1-2 heures, mais plutôt tout ce qui dépasse 1 heure.

L'autre réponse à la question susmentionnée en utilisant findne fonctionne pas, du moins pas sur Gentoo ou CentOS 5.4, elle crache un avertissement ou ne renvoie rien si l'avis de cet avertissement est suivi.

Hobodave
la source

Réponses:

22

GNU Killall peut tuer des processus plus anciens qu'un âge donné, en utilisant leur nom de processus.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
Jodie C
la source
1
Cette option n'est pas disponible sur CentOS 6.6. Version: killall (PSmisc) 22.6.
2015 à 9h36
9

Grâce à la réponse de Christopher, j'ai pu l'adapter aux éléments suivants:

find /proc -maxdepth 1 -user apache -type d -mmin +60 -exec basename {} \; \
| xargs ps | grep page.py | awk '{ print $1 }' | sudo xargs kill

-mmin était la commande de recherche qui me manquait.

Hobodave
la source
3
Je ne sais pas si -mmin convient pour détecter l'âge d'un processus.
LatinSuD
Il ne semble pas que les répertoires / proc / soient beaucoup modifiés, donc cela semble fonctionner. Cela étant dit, je ne voudrais pas prétendre que c'est impossible.
Christopher Karel du
Je ne pense pas que cela réponde à votre question car cette réponse est trop étroite et la question est plus large.
poige
Et je dirais même plus - cela ne fonctionne pas du tout: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init n'est pas répertorié malgré le nombre de temps de fonctionnement pour les jours, pas les heures. Il semble que vous ne puissiez pas compter sur l'heure de modification des répertoires de / proc /.
poige
3
Les horodatages dans / proc ne peuvent malheureusement pas dépendre de cela. Du moins plus.
dpk
8

find ne fonctionne pas toujours, tous les systèmes n'ont pas d'étimes disponibles, et cela pourrait être mon statut regex newb, mais je ne pense pas que vous ayez besoin de plus que cela:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • lister tous les processus et fournir les colonnes PID, ELAPSED (etimes = secondes), COMMAND, USER, TT (merci @ahoffman)
  • avec awk imprimer le PID où la 4e colonne (4 $, USER) contient le texte 'constructeur', et la 5e colonne (5 $, TT) contient le texte 'pts' et la colonne ELAPSED a une valeur supérieure à 600 sec (merci @amtd)

vous pouvez ensuite canaliser cela pour tuer ou quel que soit votre besoin.

eugenevd
la source
Je pense que c'est l'une des solutions les plus robustes, en particulier en termes d'utilisation de votre ps, mais je plierais les multiples grepen un seul awk, et pour des raisons de sécurité, limiter les correspondances de modèle à des colonnes particulières (pour exclure par exemple une correspondance de nom de commande constructeur, etc.)
jmtd
C'est très bien lorsque votre étendue de temps est en jours, mais ne fonctionnera pas si vous voulez tester le temps écoulé en heures, minutes ou secondes.
Vlastimil Ovčáčík
utilisez "etimes" au lieu de "etime", cela retournera le temps écoulé en secondes qui est beaucoup plus facile à analyser.
ahofmann
@jmtd & ahofmann: J'ai mis à jour selon votre commentaire. J'espère que c'est comme vous l'avez voulu
eugenevd
5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Si vous le souhaitez, vous pouvez vous alimenter psavec une liste de PID à rechercher, par exemple:

ps h -O etimes 1 2 3
poige
la source
2
etimesfonctionne uniquement pour les plus récentsps
Tino
4

Je pense que vous pouvez modifier certaines de ces réponses précédentes pour répondre à vos besoins. À savoir:

pour FILE in (find. -maxdepth 1 -user processuser -type d -mmin +60)
  do kill -9 $ (basename $ FILE) # Je ne peux jamais faire fonctionner basename avec l'exec de find. Faites-moi savoir si vous savez comment!
terminé

Ou

ps -eo pid, etime, comm | awk '$ 2! ~ /^..:..$/ && $ 3 ~ / page \ .py / {print $ 1}' | tuer -9

Je pense que le second peut mieux répondre à vos besoins. La version find finirait par nuancer d'autres processus par cet utilisateur


--Christopher Karel

Christopher Karel
la source
7
Ne pas utiliser kill -9sauf en dernier recours. Utilisez -SIGINTou -SIGTERM.
pause jusqu'à nouvel ordre.
Il s'agit du format du temps écoulé comme critère de test, et non de sa valeur. psaffichera l'heure au ^..:..$format lorsqu'elle est inférieure à une heure.
Vlastimil Ovčáčík
4
apt-get install psmisc

killall -o 1h $proc_name
Alex
la source
Pourriez-vous aider à expliquer plus sur l' psmiscutilitaire? L'OP a mentionné CentOS; est-il disponible en RPM?
Castaglia
4

Le problème

Conversion de la etimecolonne de pscommande (temps écoulé) en secondes. La spécification d'heure est dans ce format [[dd-]hh:]mm:ss. Les versions plus récentes de psont une etimescolonne qui affiche la etimevaleur en secondes.

La solution: simple fonction awk personnalisée

Cette fonction awk personnalisée prend en charge tous les formats de etimecolonne (par exemple 03-12:30:59, 00:07etc.). Il suffit de le coller dans votre script awk, c'est une solution conviviale pour les lignes.

function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}
  • sec(T) convertit T en secondes
  • Tspécification de l'heure au [[dd-]hh:]mm:ssformat (par exemple etime)
  • Cnombre de champs dans T(équivalent à la variable NF de awk)
  • Atableau de champs dans T(équivalent à la variable $ awk)
  • A[C>3?C-3:99]c'est un moyen sûr de référencer la quatrième valeur (c'est-à-dire le nombre de jours) dans l'ordre inverse. Cette approche est utile car les jours et les heures sont facultatifs. Si le tableau n'est pas assez long, il déréférencer A[99]ce qui donnera de la 0valeur. Je suppose qu'il 99est suffisamment élevé pour la plupart des cas d'utilisation.
  • renvoie les secondes sous forme d'entier

Exemple du monde réel

Ce bash oneliner va tuer le soffice.binprocessus en cours d'exécution sous l'utilisateur actuel si le processus est plus ancien que 180 secondes.

kill -9 $(ps cx -o command,etime,pid | awk '/^soffice.bin/ {if (sec($2)>180) {print $3}} function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}')
Vlastimil Ovčáčík
la source
1
BEAUCOUP mieux que les autres réponses. il gère également plusieurs procs.
Denny Weinberg
Il serait préférable de placer 'commande' ou 'args' à la fin de la liste de format 'ps' pour pouvoir grep sur la chaîne complète de commande / args. Le placer au début conduira à ps tronquer les commandes plus longues.
Maksym
1

Le lstartchamp dans psdonne un format d'heure cohérent que nous pouvons alimenter datepour convertir en secondes depuis l'époque. Ensuite, nous comparons simplement cela à l'heure actuelle.

#!/bin/bash
current_time=$(date +%s)
ps axo lstart=,pid=,cmd= |
    grep page.py |
    while read line
    do
        # 60 * 60 is one hour, multiply additional or different factors for other thresholds 
        if (( $(date -d "${line:0:25}" +%s) < current_time - 60 * 60 ))
        then
            echo $line | cut -d ' ' -f 6    # change echo to kill
        fi
    done
En pause jusqu'à nouvel ordre.
la source
0

J'ai modifié la réponse qu'ils vous ont donnée dans le post précédent

ps -eo pid,etime,comm | 
egrep '^ *[0-9]+ +([0-9]+-[^ ]*|[0-9]{2}:[0-9]{2}:[0-9]{2}) +/usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py' | 
awk '{print $1}' | 
xargs kill

L'expression régulière recherche 2 types de second argument:

  • Jours sous forme de chiffres et d'un signe moins.
  • Hours:minutes:seconds expression.

Cela devrait correspondre à tout sauf aux jeunes processus qui auraient la forme minutes:seconds.

LatinSuD
la source
Alternativement, nous pourrions essayer de le faire comme le fait PS. Soustrayez le premier argument de / proc / uptime du 22e argument de / proc / * / stat.
LatinSuD
0

C'est probablement exagéré, mais je suis devenu assez curieux pour le terminer et tester qu'il fonctionne (sur un nom de processus différent sur mon système, bien sûr). Vous pouvez tuer la capture de $useret $pidsimplifier l'expression rationnelle, que j'ai seulement ajoutée pour le débogage, et je n'ai pas eu envie de revenir en arrière. Les captures nommées de perl 5.10 raseraient quelques lignes de plus, mais cela devrait fonctionner sur les anciennes perls.

Vous devrez remplacer l'impression par un kill, bien sûr, mais je n'allais pas vraiment tuer quoi que ce soit sur mon propre système.

#!/usr/bin/perl -T
use strict; use warnings;

$ENV{"PATH"} = "/usr/bin:/bin";                                                       

my (undef,undef,$hour) = localtime(time);                                             
my $target = $hour - 2; # Flag process before this hour                               
my $grep = 'page.py';                                                   

my @proclist = `ps -ef | grep $grep`;                                                 
foreach my $proc (@proclist)                                                          
{                                                                                     
    $proc =~ /(\w+)\s+(\d+)\s+\d+\s+\d+\s+(.*?).*/;                   
    my $user = $1;                                                                    
    my $pid = $2;                                                                     
    my $stime = $3;                                                                   

    $stime =~ s/(\d+):(\d+)/$1/;                                                      

    # We're going to do a numeric compare against strings that                        
    # potentially compare things like 'Aug01' when the STIME is old                   
    # enough.  We don't care, and we want to catch those old pids, so                 
    # we just turn the warnings off inside this foreach.                              
    no warnings 'numeric';                                                            

    unless ($stime > $target)                                                         
    {                                                                                 
        print "$pid\n";                                                               
    }                                                                                 
}

Zed
la source
0

J'ai un serveur avec des dates erronées dans / proc et find ne fonctionne pas, j'ai donc écrit ce script:

#!/bin/bash

MAX_DAYS=7  #set the max days you want here
MAX_TIME=$(( $(date +'%s') - $((60*60*24*$MAX_DAYS)) ))

function search_and_destroy()
{
        PATTERN=$1
        for p in $(ps ux|grep "$PATTERN"|grep -v grep| awk '{ print $2 }')
        do
            test $(( $MAX_TIME - $(date -d "`ps -p $p -o lstart=`" +'%s') )) -ge 0 && kill -9 $p
        done
}

search_and_destroy " command1 "
search_and_destroy " command2 "
Vincent
la source
0

Version Python utilisant le ctime des entrées de processus dans /proc:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kills processes older than HOURS_DELTA hours

import os, time

SIGNAL=15
HOURS_DELTA=1

pids = [int(pid) for pid in os.listdir('/proc') if pid.isdigit()]

for pid in pids:
    if os.stat(os.path.join('/proc', str(pid))).st_ctime < time.time() - HOURS_DELTA * 3600:
        try:
            os.kill(pid, SIGNAL)
        except:
            print "Couldn't kill process %d" % pid
Eduardo Ivanec
la source
0

J'utilise ce script simple il faut deux arguments nom du processus et âge en secondes.

#!/bin/bash
# first argument name of the process to check
# second argument maximum age in seconds
# i.e kill lighttpd after 5 minutes
#   script.sh lighttpd 300 
process=$1
maximum_runtime=$2
pid=`pgrep $process`
if [ $? -ne 0 ]
then
        exit 0
fi
process_start_time=`stat /proc/$pid/cmdline --printf '%X'`
current_time=`date +%s`
let diff=$current_time-$process_start_time

if [ $diff -gt $maximum_runtime ]
then
        kill -3 $pid
fi
Sanxiago
la source
0

cela devrait fonctionner

killall --older-than 1h $proc_name

Jabir Ahmed
la source
1
Comment cela ajoute-t-il ou améliore-t-il [les réponses déjà existantes]?
Réagit du
2
@Reaces: En toute honnêteté, j'ai dû rechercher la seule réponse mentionnée --older-than et il est facile de l'oublier. Comparé aux autres réponses, c'est beaucoup plus facile, et il est également disponible maintenant sur EL7.
Sven
@Reaces cela le rend plus facile que d'écrire des scripts en utilisant awk / sed, etc. pour tuer un processus, je suppose que c'est beaucoup plus simple et plus propre
Jabir Ahmed
0

Je n'étais pas satisfait de l'autre solution, la plupart d'entre eux sont trop cryptiques (ma connaissance bash est un peu limitée) et donc je ne peux pas les personnaliser ...
J'ai créé ma propre solution, ce n'est probablement pas la meilleure mais ça marche et c'est lisible

Vous pouvez enregistrer ce script dans un fichier et le rendre exécutable (éventuellement l'appeler avec cron)

#!/bin/bash
## time in second that trigger the kill
LIMIT=10
## [] skip the grep from the process list
PROC_NAME="[m]y process name"
## etimes return the time in seconds
TIME_SEC=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$1'})
PID=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$2'})

if [ -n "$TIME_SEC" ] 
    then
    if (( $TIME_SEC > $LIMIT )); then
        kill $PID
    fi
fi
Francesco
la source
-2

72 = 3 jours 48 = 2 jours 24 = 1 jour

a1=$(TZ=72 date +%d) ps -ef| cat filex.txt | sed '/[JFMASOND][aepuco][nbrylgptvc] '$a1'/!d' | awk '{ print $2 " " $5 " " $6 }' > file2.txt

Ça marche :)

onkar
la source
1
C'est peut-être vrai, mais c'est assez difficile à lire et à apprendre. Pensez à reformater avec quelques nouvelles lignes et d'autres choses ... les scripts sont meilleurs que les lignes simples pour l'instruction.
Falcon Momot