Como posso matar um processo e ter certeza de que o PID não foi reutilizado

40

Suponha, por exemplo, que você tenha um script de shell semelhante a:

longrunningthing &
p=$!
echo Killing longrunningthing on PID $p in 24 hours
sleep 86400
echo Time up!
kill $p

Deveria fazer o truque, não deveria? Exceto que o processo pode ter terminado mais cedo e seu PID pode ter sido reciclado, o que significa que algum trabalho inocente recebe uma bomba na fila de sinais. Na prática, isso possivelmente importa, mas ainda assim está me preocupando. Hackear tudo para cair morto por si só, ou manter / remover seu PID no FS faria, mas estou pensando na situação genérica aqui.

FJL
fonte
3
Você garante que, se seu processo de destino morrer, ele matará seu assassino no processo.
precisa saber é o seguinte
2
Use killallquais correspondências no nome, para que pelo menos você esteja apenas matando um processo com o mesmo nome que longrunningthing. Supondo que você terá apenas uma dessas opções por vez.
LawrenceC
8
Você pode salvar a hora de início do processo original e, antes de matar, verifique se a hora de início do processo com esse pid corresponde ao que você salvou. O par pid, start-time é um identificador exclusivo para os processos no Linux.
Bakuriu 26/01
11
Posso perguntar por que você precisa disso? qual é a coisa fundamental que você está tentando alcançar? (algo que funcione continuamente, mas é resetado a cada 24h?)
Olivier Dulac
2
@mikeserv Um processo não pode garantir que algo aconteça no caso de sua própria morte.
precisa saber é

Respostas:

29

O melhor seria usar o timeoutcomando, se você o tiver, para isso:

timeout 86400 cmd

A implementação atual (8.23) GNU pelo menos funciona usando alarm()ou equivalente enquanto aguarda o processo filho. Parece não proteger contra a SIGALRMentrega entre waitpid()retorno e timeoutsaída (cancelamento efetivo desse alarme ). Durante essa pequena janela, timeoutpode até escrever mensagens no stderr (por exemplo, se a criança despejar um núcleo), o que aumentaria ainda mais essa janela de corrida (indefinidamente se o stderr for um canal completo, por exemplo).

Pessoalmente, posso conviver com essa limitação (que provavelmente será corrigida em uma versão futura). timeouttambém terá um cuidado extra para relatar o status de saída correto, lidar com outros casos de canto (como o SIGALRM bloqueado / ignorado na inicialização, lidar com outros sinais ...) melhor do que você provavelmente conseguiria fazer manualmente.

Como uma aproximação, você pode escrever perlcomo:

perl -MPOSIX -e '
  $p = fork();
  die "fork: $!\n" unless defined($p);
  if ($p) {
    $SIG{ALRM} = sub {
      kill "TERM", $p;
      exit 124;
    };
    alarm(86400);
    wait;
    exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
  } else {exec @ARGV}' cmd

Existe um timelimitcomando em http://devel.ringlet.net/sysutils/timelimit/ (antecede o GNU timeoutem alguns meses).

 timelimit -t 86400 cmd

Esse usa um alarm()mecanismo semelhante, mas instala um manipulador SIGCHLD(ignorando crianças paradas) para detectar a morte da criança. Ele também cancela o alarme antes de executar waitpid()(que não cancela a entrega, SIGALRMse estava pendente, mas da maneira como está escrito, não vejo problema) e mata antes de ligar waitpid()(por isso, não é possível matar um pid reutilizado) )

O netpipes também possui um timelimitcomando. Essa é anterior a todas as outras por décadas, adota outra abordagem, mas não funciona corretamente para comandos interrompidos e retorna um 1status de saída após o tempo limite.

Como resposta mais direta à sua pergunta, você pode fazer algo como:

if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
  kill "$p"
fi

Ou seja, verifique se o processo ainda é filho nosso. Novamente, há uma pequena janela de corrida (entre psrecuperar o status desse processo e killmatá-lo) durante o qual o processo pode morrer e seu pid ser reutilizado por outro processo.

Com algumas conchas ( zsh, bash, mksh), você pode passar especificações trabalho em vez de PIDs.

cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status

Isso só funciona se você gerar apenas um trabalho em segundo plano (caso contrário, nem sempre é possível obter a especificação de trabalho correta).

Se isso é um problema, basta iniciar uma nova instância do shell:

bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd

Isso funciona porque o shell remove o trabalho da tabela de trabalhos quando a criança morre. Aqui, não deve haver nenhuma janela de corrida, pois no momento em que o shell chama kill(), o sinal SIGCHLD não foi tratado e o pid não pode ser reutilizado (pois não foi esperado), ou foi tratado e o sinal o trabalho foi removido da tabela de processos (e killreportaria um erro). bashé kill, pelo menos, blocos SIGCHLD antes de ele acessa sua tabela de trabalho para expandir o %e desbloqueia-lo após o kill().

Outra opção para evitar a interrupção desse sleepprocesso, mesmo após a cmdmorte, com bashou ksh93é usar um cano com, em read -tvez de sleep:

{
  {
    cmd 4>&1 >&3 3>&- &
    printf '%d\n.' "$!"
  } | {
    read p
    read -t 86400 || kill "$p"
  }
} 3>&1

Aquele ainda tem condições de corrida e você perde o status de saída do comando. Ele também assume cmdque não fecha seu fd 4.

Você pode tentar implementar uma solução sem raça, perlcomo:

perl -MPOSIX -e '
   $p = fork();
   die "fork: $!\n" unless defined($p);
   if ($p) {
     $SIG{CHLD} = sub {
       $ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
       sigprocmask(SIG_BLOCK, $ss, $oss);
       waitpid($p,WNOHANG);
       exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
           unless $? == -1;
       sigprocmask(SIG_UNBLOCK, $oss);
     };
     $SIG{ALRM} = sub {
       kill "TERM", $p;
       exit 124;
     };
     alarm(86400);
     pause while 1;
   } else {exec @ARGV}' cmd args...

(apesar de precisar ser aprimorado para lidar com outros tipos de caixas de canto).

Outro método sem raça pode estar usando grupos de processos:

set -m
((sleep 86400; kill 0) & exec cmd)

No entanto, observe que o uso de grupos de processos pode ter efeitos colaterais se houver E / S em um dispositivo terminal envolvido. Porém, ele tem o benefício adicional de matar todos os outros processos extras gerados cmd.

Stéphane Chazelas
fonte
4
Por que não mencionar o melhor método primeiro?
Deltab
2
@eltab: timeoutnão é portátil, a resposta mencionou uma solução portátil primeiro.
precisa saber é
11
@deltab: fornece informações sobre como as coisas funcionam e, especialmente, como a abordagem do "senso comum" pode falhar (Stephane prefere ensinar alguém a pescar primeiro, o que eu gosto). Um é esperado para ler toda a resposta
Olivier Dulac
@ Stephanie: para a "obtenção da especificação correta de tarefas nem sempre é possível com segurança": você não pode contar primeiro a saída jobse depois saber que (como é seu próprio shell, no qual você tem controle sobre o que acontece a seguir), o próximo plano de fundo o trabalho será N + 1? [então você pode salvar N e depois matar% N + 1])
Olivier Dulac
11
@OlivierDulac, que presumiria que nenhum trabalho passado foi encerrado no momento em que você inicia um novo (os shells reutilizam os números de trabalho).
Stéphane Chazelas
28

Em geral, você não pode. Todas as respostas dadas até agora são heurísticas de bugs. Há apenas um caso em que você pode usar o pid com segurança para enviar sinais: quando o processo de destino é filho direto do processo que enviará o sinal e o pai ainda não o esperou. Nesse caso, mesmo que ele tenha saído, o pid é reservado (é o que é um "processo de zumbi") até que o pai espere. Não conheço nenhuma maneira de fazer isso de maneira limpa com a concha.

Uma maneira alternativa segura de eliminar processos é iniciá-los com um conjunto tty de controle em um pseudo-terminal para o qual você possui o lado mestre. Você pode então enviar sinais através do terminal, por exemplo, escrevendo o caractere para SIGTERMou SIGQUITsobre o pty.

Outra maneira mais conveniente para o script é usar uma screensessão nomeada e enviar comandos para a sessão da tela para finalizá-la. Esse processo ocorre em um soquete pipe ou unix nomeado de acordo com a sessão de tela, que não será reutilizado automaticamente se você escolher um nome exclusivo e seguro.

R ..
fonte
4
Não vejo por que isso não poderia ser feito em conchas. Eu dei várias soluções.
Stéphane Chazelas 26/01
3
Poderia, por favor, dar uma explicação e algum tipo de discussão quantitativa sobre janelas de corrida e outras desvantagens? Sem isso, "Todas as respostas dadas até agora são heurísticas de buggy" é apenas um confronto desnecessariamente desnecessário, sem nenhum benefício.
Peterph
3
@peterph: Em geral, qualquer uso de um pid é uma corrida TOCTOU - não importa como você verifique se ele ainda se refere ao mesmo processo que você espera que ele se refira, ele pode deixar de se referir a esse processo e se referir a alguns novos processe no intervalo antes de usá-lo (enviando o sinal). A única maneira de evitar isso é ser capaz de bloquear a liberação / reutilização do pid, e o único processo que pode fazer isso é o pai direto.
R ..
2
@ StéphaneChazelas: Como você evita que o shell aguarde um pouco do processo de segundo plano que terminou? Se você pode fazer isso, o problema é facilmente solucionável no caso de o OP precisar.
R ..
5
@ Peter: "A janela da corrida é pequena" não é uma solução. E a raridade da corrida depende de atribuição seqüencial de pids. Erros que fazem com que algo muito ruim aconteça uma vez por ano são muito piores do que erros que acontecem o tempo todo porque são praticamente impossíveis de diagnosticar e corrigir.
R ..
10
  1. Ao iniciar o processo, salve seu horário de início:

    longrunningthing &
    p=$!
    stime=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    echo "Killing longrunningthing on PID $p in 24 hours"
    sleep 86400
    echo Time up!
    
  2. Antes de tentar interromper o processo, pare com isso (isso não é realmente essencial, mas é uma maneira de evitar as condições de corrida: se você parar o processo, o pid não poderá ser reutilizado)

    kill -s STOP "$p"
    
  3. Verifique se o processo com esse PID tem a mesma hora de início e, se sim, mate-o, caso contrário, deixe o processo continuar:

    cur=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    if [ "$cur" = "$stime" ]
    then
        # Okay, we can kill that process
        kill "$p"
    else
        # PID was reused. Better unblock the process!
        echo "long running task already completed!"
        kill -s CONT "$p"
    fi
    

Isso funciona porque pode haver apenas um processo com o mesmo PID e a hora de início em um determinado sistema operacional.

Parar o processo durante a verificação torna as condições da corrida um problema. Obviamente, isso tem o problema de que, algum processo aleatório pode ser interrompido por alguns milissegundos. Dependendo do tipo de processo, isso pode ou não ser um problema.


Pessoalmente, eu simplesmente usaria python e psutillida com a reutilização do PID automaticamente:

import time

import psutil

# note: it would be better if you were able to avoid using
#       shell=True here.
proc = psutil.Process('longrunningtask', shell=True)
time.sleep(86400)

# PID reuse handled by the library, no need to worry.
proc.terminate()   # or: proc.kill()
Bakuriu
fonte
Regras de Python no UNIX ... Não sei por que mais respostas não começam por aí, pois tenho certeza de que a maioria dos sistemas não proíbe o uso.
Sr. Mascaro
Eu usei um esquema semelhante (usando o horário de início) antes, mas suas habilidades de script sh são mais legais que as minhas! Obrigado.
FJL 26/01
Isso significa que você está potencialmente interrompendo o processo errado. Observe que o ps -o start=formato muda de 18:12 para Jan26 depois de um tempo. Cuidado com as alterações de horário de verão também. Se no Linux, você provavelmente prefere TZ=UTC0 ps -o lstart=.
Stéphane Chazelas
@ StéphaneChazelas Sim, mas você continua depois. Eu disse explicitamente: dependendo do tipo de tarefa que esse processo está executando, você pode ter alguns problemas para interromper alguns milissegundos. Obrigado pela dica sobre lstart, eu vou editá-lo no.
Bakuriu
Observe que (a menos que seu sistema limite o número de processos por usuário), é fácil para qualquer pessoa preencher a tabela de processos com zumbis. Uma vez que restam apenas 3 pids disponíveis, é fácil para qualquer pessoa iniciar centenas de processos diferentes com o mesmo pid dentro de um único segundo. Portanto, estritamente falando, seu "pode ​​haver apenas um processo com o mesmo PID e a hora de início em um determinado sistema operacional" não é necessariamente verdadeiro.
Stéphane Chazelas
7

Em um sistema linux, você pode garantir que um pid não seja reutilizado mantendo seu espaço de nome pid ativo. Isso pode ser feito através do /proc/$pid/ns/pidarquivo

  • man namespaces -

    Vincule a montagem (consulte mount(2)) um dos arquivos neste diretório a outro local do sistema de arquivos, mantendo o espaço de nomes correspondente do processo especificado por pid ativo, mesmo que todos os processos atualmente no espaço de nomes sejam encerrados.

    Abrir um dos arquivos neste diretório (ou um arquivo que é montado em ligação a um desses arquivos) retorna um identificador de arquivo para o espaço para nome correspondente do processo especificado por pid. Enquanto esse descritor de arquivo permanecer aberto, o espaço para nome permanecerá ativo, mesmo se todos os processos no espaço para nome terminarem. O descritor de arquivo pode ser passado para setns(2).

Você pode isolar um grupo de processos - basicamente qualquer número de processos - colocando o nome deles init.

  • man pid_namespaces -

    O primeiro processo criado em um novo espaço para nome (ou seja, o processo criado usando clone(2) o sinalizador CLONE_NEWPID ou o primeiro filho criado por um processo após uma chamada para unshare(2)usar o sinalizador CLONE_NEWPID ) possui o PID 1 e é o initprocesso para o espaço para nome ( ver init(1)) . Um processo filho órfão dentro do espaço para nome será reparado nesse processo em vez de init(1) (a menos que um dos ancestrais da criança no mesmo espaço para nome PID empregue o comando prctl(2) PR_SET_CHILD_SUBREAPER para marcar a si próprio como o ceifador de processos descendentes órfãos) .

    Se o initprocesso de um namespace PID terminar, o kernel encerrará todos os processos no namespace por meio de um sinal SIGKILL . Esse comportamento reflete o fato de que o initprocesso é essencial para a operação correta de um espaço para nome PID .

O util-linuxpacote fornece muitas ferramentas úteis para manipular os espaços para nome. Por exemplo, no unshareentanto, se você ainda não organizou seus direitos em um espaço para nome de usuário, serão necessários direitos de superusuário:

unshare -fp sh -c 'n=
    echo "PID = $$"
    until   [ "$((n+=1))" -gt 5 ]
    do      while   sleep 1
            do      date
            done    >>log 2>/dev/null   &
    done;   sleep 5' >log
cat log; sleep 2
echo 2 secs later...
tail -n1 log

Se você não organizou um espaço para nome de usuário, ainda poderá executar comandos arbitrários com segurança, removendo imediatamente os privilégios. O runusercomando é outro binário (não setuid) fornecido pelo util-linuxpacote e a incorporação pode se parecer com:

sudo unshare -fp runuser -u "$USER" -- sh -c '...'

...e assim por diante.

No exemplo acima, duas opções são passadas para unshare(1)o --forksinalizador que torna o sh -cprocesso invocado o primeiro filho criado e garante seu initstatus, e o --pidsinalizador que instrui unshare(1)a criar um espaço para nome pid.

O sh -cprocesso gera cinco shells filhos em segundo plano - cada um com um whileloop inifinito que continuará anexando a saída dateaté o final do logtempo, enquanto sleep 1retornar verdadeiro. Após gerar esses processos, shsão necessários sleep5 segundos adicionais e termina.

Talvez valha a pena notar que, se a -fbandeira não fosse usada, nenhum dos whileloops em segundo plano terminaria, mas com ela ...

SAÍDA:

PID = 1
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
2 secs later...
Mon Jan 26 19:17:48 PST 2015
mikeserv
fonte
Resposta interessante que parece ser robusta. Provavelmente um pouco exagerado para o uso básico, mas vale a pena pensar.
Uriel
Não vejo como ou por que manter um espaço de nome PID ativo impede a reutilização de um PID. A própria página de manual que você cita - Enquanto esse descritor de arquivo permanecer aberto, o espaço para nome permanecerá ativo, mesmo que todos os processos no espaço para nome terminem - sugere que os processos ainda podem terminar (e, portanto, presumivelmente, seu ID do processo será reciclado). O que manter vivo o espaço para nome do PID tem a ver com impedir que o próprio PID seja reutilizado por outro processo?
Davmac
5

Considere tornar seu longrunningthingcomportamento um pouco melhor, um pouco mais parecido com um daemon. Por exemplo, você pode criar um pidfile que permitirá pelo menos algum controle limitado do processo. Existem várias maneiras de fazer isso sem modificar o binário original, todas envolvendo um wrapper. Por exemplo:

  1. um script de wrapper simples que iniciará o trabalho necessário em segundo plano (com redirecionamento de saída opcional), grave o PID desse processo em um arquivo e aguarde a conclusão do processo (usando wait) e remova o arquivo. Se durante a espera o processo é interrompido, por exemplo, por algo como

    kill $(cat pidfile)
    

    o wrapper apenas garantirá que o pidfile seja removido.

  2. um wrapper de monitor, que colocará seu próprio PID em algum lugar e captará (e responderá) os sinais enviados a ele. Exemplo simples:

    #!/bin/bash
    p=0
    trap killit USR1

    killit () {
        printf "USR1 caught, killing %s\n" "$p"
        kill -9 $p
    }

    printf "monitor $$ is waiting\n"
    therealstuff &
    p=%1
    wait $p
    printf "monitor exiting\n"

Agora, como @R .. e @ StéphaneChazelas apontaram, essas abordagens geralmente têm uma condição de corrida em algum lugar ou impõem uma restrição ao número de processos que você pode gerar. Além disso, ele não lida com os casos, nos quais o longrunningthinggarfo pode e as crianças se separam (o que provavelmente não é o problema na pergunta original).

Com os kernels Linux recentes (leia alguns anos), isso pode ser bem tratado usando o cgroups , ou seja, o freezer - que, suponho, é o que alguns sistemas modernos Linux init usam.

peterph
fonte
Obrigado e a todos. Estou lendo tudo agora. O ponto longrunningthingé que você não tem controle sobre o que é. Também dei um exemplo de script de shell, porque explicava o problema. Eu gosto da sua e de todas as outras soluções criativas aqui, mas se você estiver usando Linux / bash, há um "tempo limite" incorporado para isso. Suponho que eu deveria obter a fonte disso e ver como isso acontece!
FJL 26/01
@FJL, nãotimeout é um shell embutido. Houve várias implementações de um comando para Linux, uma delas foi recentemente (2008) adicionada ao GNU coreutils (portanto, não específica do Linux), e é isso que a maioria das distribuições Linux usa atualmente. timeout
Stéphane Chazelas
@ Stéphane - Obrigado - Eu encontrei referências aos coreutils do GNU. Eles podem ser portáteis, mas, a menos que esteja no sistema básico, não é possível confiar nele. Estou mais interessado em saber como ele funciona, apesar de observar seu comentário em outro lugar, sugerindo que ele não é 100% confiável. Dada a maneira como este tópico foi, não estou surpreso!
FJL
1

Se você estiver executando no Linux (e alguns outros * nixes), poderá verificar se o processo que pretende matar ainda é usado e se a linha de comando corresponde ao seu longo processo. Algo como :

echo Time up!
grep -q longrunningthing /proc/$p/cmdline 2>/dev/null
if [ $? -eq 0 ]
then
  kill $p
fi

Uma alternativa pode ser verificar por quanto tempo o processo que você pretende matar está em execução, com algo parecido ps -p $p -o etime=. Você pode fazê-lo extraindo essas informações /proc/$p/stat, mas isso seria complicado (o tempo é medido em instantes e você também precisará usar o tempo de atividade do sistema /proc/stat).

De qualquer forma, você geralmente não pode garantir que o processo não seja substituído após sua verificação e antes de matá-la.

Uriel
fonte
Isso ainda não está correto, porque não se livra da condição de corrida.
Strcat
@strcat De fato, não há garantia de sucesso, mas a maioria dos scripts nem se preocupa em fazer essa verificação e apenas mata um cat pidfileresultado sem rodeios . Não me lembro de uma maneira limpa de fazê-lo apenas com casca. A resposta namespace proposta parece um um intersting no entanto ...
Uriel
-1

Esta é realmente uma pergunta muito boa.

A maneira de determinar a exclusividade do processo é observar (a) onde ele está na memória; e (b) o que essa memória contém. Para ser específico, queremos saber onde está na memória o texto do programa para a chamada inicial, porque sabemos que a área de texto de cada encadeamento ocupará um local diferente na memória. Se o processo morrer e outro for lançado com o mesmo pid, o texto do programa para o novo processo não ocupará o mesmo lugar na memória e não conterá a mesma informação.

Portanto, imediatamente após o lançamento do processo, faça md5sum /proc/[pid]/mapse salve o resultado. Mais tarde, quando você quiser interromper o processo, faça outro md5sum e compare-o. Se combinar, mate o pid. Se não, não.

para ver isso por si mesmo, inicie duas conchas do bash idênticas. Examine o /proc/[pid]/mapspara eles e você verá que eles são diferentes. Por quê? Porque, mesmo sendo o mesmo programa, eles ocupam locais diferentes na memória e os endereços da pilha são diferentes. Portanto, se seu processo morrer e seu PID for reutilizado, mesmo com o mesmo comando sendo reiniciado com os mesmos argumentos , o arquivo "maps" será diferente e você saberá que não está lidando com o processo original.

Veja: proc man page para detalhes.

Observe que o arquivo /proc/[pid]/statjá contém todas as informações que outros pôsteres mencionaram em suas respostas: idade do processo, pai ou mãe, etc. Este arquivo contém informações estáticas e dinâmicas, portanto, se você preferir usar esse arquivo como base de comparação, depois de iniciar o seu longrunningthing, você precisa extrair os seguintes campos estáticos do statarquivo e salvá-los para comparação mais tarde:

pid, nome do arquivo, número do pai, identificação do grupo de processos, terminal de controle, tempo do processo iniciado após a inicialização do sistema, tamanho do conjunto residente, endereço do início da pilha,

juntos, os itens acima identificam exclusivamente o processo e, portanto, isso representa outro caminho a percorrer. Na verdade, você pode se safar com nada além de "pid" e "processo de tempo iniciado após a inicialização do sistema" com alto grau de confiança. Simplesmente extraia esses campos do statarquivo e salve-os em algum lugar ao iniciar seu processo. Mais tarde, antes de matá-lo, extraia-o novamente e compare. Se eles corresponderem, você terá certeza de que está observando o processo original.

Michael Martinez
fonte
11
Isso geralmente não funciona como /proc/[pid]/mapsalterações ao longo do tempo, pois a memória extra é alocada ou a pilha cresce ou novos arquivos são mapeados ... E o que significa imediatamente após o lançamento ? Depois que todas as bibliotecas foram mapeadas? Como você determina isso?
Stéphane Chazelas
Estou fazendo um teste agora no meu sistema com dois processos, um aplicativo java e outro servidor cfengine. A cada 15 minutos eu faço md5sumem seus arquivos de mapas. Vou deixá-lo funcionar por um dia ou dois e relatar aqui com os resultados.
Michael Martinez
@ StéphaneChazelas: Estive verificando meus dois processos para 16 horas agora, e não houve nenhuma mudança na md5sum
Michael Martinez
-1

Outra maneira seria verificar a idade do processo antes de matá-lo. Dessa forma, você pode ter certeza de que não está matando um processo que não é gerado em menos de 24 horas. Você pode adicionar uma ifcondição com base nisso antes de interromper o processo.

if [[ $(ps -p $p -o etime=) =~ 1-. ]] ; then
    kill $p
fi

Essa ifcondição verificará se o ID do processo $pé inferior a 24 horas (86400 segundos).

PS: - O comando ps -p $p -o etime=terá o formato<no.of days>-HH:MM:SS

Sree
fonte
O mtimede /proc/$pnada tem a ver com a hora de início do processo.
Stéphane Chazelas
Obrigado @ StéphaneChazelas. Você está certo. Eu editei a resposta para alterar a ifcondição. Por favor, sinta-se livre para comentar se o seu buggy.
Sree
-3

O que faço é, depois de ter encerrado o processo, fazê-lo novamente. Toda vez que faço isso, a resposta volta: "não existe esse processo"

allenb   12084  5473  0 08:12 pts/4    00:00:00 man man
allenb@allenb-P7812 ~ $ kill -9 12084
allenb@allenb-P7812 ~ $ kill -9 12084
bash: kill: (12084) - No such process
allenb@allenb-P7812 ~ $ 

Não poderia ser mais simples e eu venho fazendo isso há anos sem problemas.

Allen
fonte
Isso está respondendo à pergunta "como posso piorar as coisas", e não à "como posso corrigir isso".
Stéphane Chazelas