Como eu mato processos anteriores a "t"?


14

Primeiro, sim, eu já vi essa pergunta:

Encontre (e mate) processos antigos

As respostas estão incorretas e não funcionam. Votei e comentei em conformidade.

Os processos que eu quero matar são assim quando listados com 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

Eu estou olhando para configurar um cron diário simples que irá encontrar e matar todos os page.pyprocessos anteriores a uma hora.

A resposta aceita na pergunta mencionada não funciona, pois não corresponde a um intervalo de vezes, simplesmente corresponde a processos que foram executados de 7 dias a 7 dias 23 horas 59 minutos e 59 segundos. Não quero matar processos em execução de uma a duas horas, mas algo maior que 1 hora.

A outra resposta para a pergunta acima mencionada findnão funciona, pelo menos não no Gentoo ou no CentOS 5.4, ou gera um aviso ou não retorna nada se a recomendação desse aviso for seguida.

Respostas:


21

O GNU Killall pode matar processos anteriores a uma determinada idade, usando o nome do processo.

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

1
Essa opção não está disponível no CentOS 6.6. Versão: killall (PSmisc) 22.6.
Onnonymous 28/09/15

9

Graças à resposta de Christopher, pude adaptá-lo ao seguinte:

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

-mmin foi o comando find que estava faltando.


3
Não tenho certeza se -mmin é adequado para detectar a idade de um processo.
LatinSuD

Não parece que os diretórios / proc / sejam muito modificados, então isso parece funcionar. Dito isto, eu não gostaria de afirmar que é impossível.
Christopher Karel

Não acho que isso responda à sua pergunta, pois ela é muito estreita e a pergunta é mais ampla.
Poige

E eu diria ainda mais - não funciona: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init não está sendo listado apesar das contagens de tempo de atividade por dias, não horas. Parece que você não pode confiar no tempo de modificação de diretórios do / proc /.
Poige 29/05

3
Infelizmente, os carimbos de data / hora em / proc não podem depender disso. Pelo menos não mais.
DPK

8

find nem sempre funciona, nem todo sistema tem etimes disponíveis, e pode ser o meu status regex newb, mas acho que você não precisa de nada além disso:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • listar todos os processos e fornecer colunas PID, ELAPSED (etimes = segundos), COMANDO, USUÁRIO, TT (obrigado @ahoffman)
  • com awk imprima o PID onde a quarta coluna (US $ 4, USER) contém o texto 'construtor' e a quinta coluna (US $ 5, TT) contém o texto 'pts' e a coluna ELAPSED tem um valor maior que 600 s (obrigado @amtd)

você pode canalizar isso para matar ou qualquer que seja sua necessidade.


Eu acho que essa é uma das soluções mais robustas, especialmente em termos de uso ps, mas eu dobraria os múltiplos greps no único awke, por segurança, restringiria as correspondências de padrões a colunas específicas (para excluir, por exemplo, um nome de comando correspondente )
jmtd

Isso é bom quando seu escopo de tempo é em dias, mas não funcionará se você quiser testar o tempo decorrido em horas, minutos ou segundos.
Vlastimil Ovčáčík

use "etimes" em vez de "etime", isso retornará o tempo decorrido em segundos, o que é muito mais fácil de analisar.
ahofmann 20/09/19

@ jmtd & ahofmann: Eu atualizei de acordo com seu comentário. Espero que este é como você destina
eugenevd

5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Se você quiser, pode alimentar pscom a lista de PIDs a serem pesquisados, por exemplo:

ps h -O etimes 1 2 3

2
etimesfunciona apenas para os mais novosps
Tino

4

Acho que você pode modificar algumas dessas respostas anteriores para atender às suas necessidades. Nomeadamente:

para FILE em (localize. -maxdepth 1 -user processuser -type d -mmin +60)
  do-kill $ -9 (nome_de_base $ FILE) # Eu nunca consigo obter o nome-de-base para trabalhar com o exec do find. Deixe-me saber se você sabe como!
feito

Ou

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

Eu acho que o segundo pode melhor atender às suas necessidades. A versão find acabaria com outros processos desse usuário -


Christopher Karel


7
Não use, kill -9exceto como último recurso. Use -SIGINTou -SIGTERM.
Pausado até novo aviso.

Isso está usando o formato do tempo decorrido como critério de teste, não como seu valor. psproduzirá a hora no ^..:..$formato quando for menos de uma hora.
Vlastimil Ovčáčík

4
apt-get install psmisc

killall -o 1h $proc_name

Você poderia ajudar a explicar mais sobre o psmiscutilitário? O OP mencionou o CentOS; está disponível como um RPM?
Castaglia 31/03

4

O problema

Convertendo a etimecoluna de pscomando (tempo decorrido) em segundos. A especificação de hora está neste formato [[dd-]hh:]mm:ss. As versões mais recentes do pstêm uma etimescoluna que gera etimevalor em segundos.

A solução: função awk personalizada simples

Esta função personalizada do awk suporta todos os formatos de etimecoluna (por exemplo 03-12:30:59, 00:07etc.). Basta colá-lo no seu script awk, é uma solução amigável para uma só pessoa.

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) converte T em segundos
  • T especificação de tempo em [[dd-]hh:]mm:ss formato (por exemplo etime)
  • C contagem de campos em T (equivalente à variável NF do awk)
  • A matriz de campos em T (equivalente à variável $ do awk)
  • A[C>3?C-3:99]essa é uma maneira segura de fazer referência ao quarto valor (ou seja, número de dias) na ordem inversa. Essa abordagem é útil porque dias e horas são opcionais. Se a matriz não for longa o suficiente, desreferenciará o A[99]que produzirá0 valor. Suponho que 99seja alto o suficiente para a maioria dos casos de uso.
  • retorna segundos como inteiro

Exemplo do mundo real

Esse bash oneliner interromperá o soffice.binprocesso em execução no usuário atual se o processo tiver mais de 180 segundos.

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}')

1
MUITO melhor que as outras respostas. Ele também lida com vários procs.
Denny Weinberg

Seria melhor colocar 'command' ou 'args' no final da lista de formatos 'ps' para poder grep na cadeia de comandos / args completa. Colocá-lo no início levará o ps a truncar os comandos mais longos.
Maksym

1

O lstartcampo em psfornece um formato de hora consistente que podemos alimentar datepara converter em segundos desde a época. Depois, comparamos isso com o horário atual.

#!/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

0

Modifiquei a resposta que eles deram no post anterior

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

A expressão regular procura 2 tipos de segundo argumento:

  • Dias na forma de dígitos e um sinal de menos.
  • Hours:minutes:seconds expressão.

Isso deve corresponder a tudo, exceto processos jovens que teriam a forma minutes:seconds.


Alternativamente, poderíamos tentar fazê-lo da maneira que o PS faz. Subtraia o primeiro argumento de / proc / uptime do 22º argumento de / proc / * / stat.
LatinSuD

0

Provavelmente é um exagero, mas fiquei curioso o suficiente para finalizá-lo e testar se ele funciona (em um nome de processo diferente no meu sistema, é claro). Você pode matar a captura $usere$pid simplificar o regexp, que eu adicionei apenas para depuração, e não senti vontade de voltar. As capturas nomeadas do perl 5.10 eliminariam mais algumas linhas, mas isso deve funcionar em perls mais antigos.

Você precisará substituir a impressão por uma morte, é claro, mas eu não estava disposto a matar nada no meu próprio sistema.

#!/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";                                                               
    }                                                                                 
}


0

Eu tenho um servidor com datas erradas em / proc e encontrar não funciona, então eu escrevi este 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 "

0

Versão Python usando o ctime das entradas do processo em /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

0

Eu uso esse script simples que leva dois argumentos, nome do processo e idade em segundos.

#!/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

0

isso deve funcionar

killall --older-than 1h $proc_name


1
Como isso adiciona ou melhora [as respostas já existentes]?
Reaces

2
@ Reaces: Com toda a justiça, eu tive que procurar a resposta mencionando --older-than e é fácil ignorar. Comparado com as outras respostas, isso é muito mais fácil e também está disponível agora no EL7.
Sven

@Reaces isso só faz com que seja mais fácil do que escrever scripts usando awk / sed etc para matar um processo, isso eu suponho que é muito mais simples e mais limpo
Jabir Ahmed

0

Eu não estava satisfeito com a outra solução, a maioria delas é muito enigmática (meu conhecimento do bash é meio limitado) e, portanto, não posso personalizá-las ...
Eu criei minha própria solução, provavelmente não é a melhor, mas funciona e é legível

Você pode salvar esse script em um arquivo e torná-lo executável (eventualmente, chame-o usando 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

-2

72 = 3 dias 48 = 2 dias 24 = 1 dia

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

funciona :)


1
Pode muito bem ser, mas é muito difícil de ler e aprender. Considere reformatar com algumas novas linhas e outras coisas ... scripts são melhores do que uma linha para instruções.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.