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.