Como obter o pid para o último aplicativo em segundo plano

3

Seguindo esta pergunta: Como obter o pid do último comando executado no shell script?

O segmento é bom e claro, mas e se o comando realmente não exigir um '&' no final, a fim de se fundo? Então é possível obter o PID?

Nota: NÃO quero usar ps e grep ; Estou perguntando porque, teoricamente, logo após a execução de um comando, o PID desse processo deveria ser encontrado.

Um exemplo de aplicativo que se expõe - não é esse que eu preciso, eu preciso de uma solução genérica para coisas como qualquer coisa que passe por fundo sozinha (algumas forçando-a sem opção de "primeiro plano") - - mas para testar uma solução, isso funcionará bem:

script my-app:

#!/bin/bash

(
sleep 10
echo test
sleep 5
) &

como você pode ver o '&' está dentro do script e não do lado de fora, então, iniciar não exigirá &:

./my-app ; echo $! | od -c ; jobs | od -c
0000000  \n
0000001
0000000

$! é nulo e jobs não retorna nada. Ainda assim, após 10 segundos, uma mensagem de "teste" aparecerá; também:

ps x | grep my-app | grep -v grep        
14986 pts/5    S      0:00 /bin/bash ./my-app

Atualize, depois de alguns comentários dizendo que os trabalhos não se aplicam aqui; Eu estou esperando por uma solução e minha esperança não se limita a bash:)

    
por user40404 21.10.2015 / 15:13

3 respostas

2

Para o fundo , esse aplicativo bifurca um processo filho e sai do pai. O shell sabe do processo pai, que é o que ele se autodestrou antes de executar o comando em si, mas não tem visibilidade sobre os filhos ou netos que esse processo pode ter gerado.

Um exemplo mais simples de tal comando de background seria:

$ sh -c 'ps -j; sleep 10 &'
  PID  PGID   SID TTY          TIME CMD
 6562  6562 14469 pts/13   00:00:00 sh
 6563  6562 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

Meu zsh sabe sobre esse sh process e seu grupo de processos.

No entanto, tudo o que se vê é que o processo 6562 está saindo. Não tem como saber que o processo 6562 gerou um 6563.

$ ps -j
  PID  PGID   SID TTY          TIME CMD
 6564  6562 14469 pts/13   00:00:00 sleep
 6565  6565 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

No entanto, você pode ver que o processo executando sleep também está nesse grupo de processos 6562 (embora não haja nada que pare os comandos, inicie novos grupos de processos ou até sessões (como os daemons geralmente fazem)).

Esses grupos de processos são criados apenas quando o shell é interativo.

Outra coisa que você pode fazer é:

cmd | cat &
wait

Se os processos que o cmd gera não fecharem o stdout, então cat não morrerá até que todos tenham morrido.

    
por 21.10.2015 / 18:57
2

Isso não é possível em geral. Pode ser possível no seu caso específico.

Logo depois de executar um comando de segundo plano, o ID do processo pode ser descoberto no pai . Se você executar um comando em primeiro plano (um filho do programa mestre) e esse comando executar um comando em segundo plano (um neto do programa mestre), o programa mestre não terá visibilidade direta em seu neto: tudo o que sabe é que é executar um processo filho, que agora foi encerrado.

O kernel mantém o controle dos relacionamentos filho-pai-processo. Você pode executar ps -o ppid= -p $pid para ver o ID do processo pai do processo cujo ID é $pid . O kernel não acompanha o avô de um processo. Além disso, se o pai morrer, o processo é adotado pelo init (processo número 1), portanto, seu ID de processo pai será 1 daquele ponto em diante.

Existem vários outros atributos do processo que são herdados e que você pode tentar acompanhar. No entanto, o neto pode se divorciar de qualquer um desses atributos. Se o neto tiver a intenção de ser executado como um daemon, ele provavelmente tentará se isolar o máximo possível (do filho intermediário ou do próprio neto), de modo que ele não fique vinculado à sua sessão interativa e não o faça. arriscar ser pego em qualquer coisa que aconteça com esta sessão.

Você pode procurar processos no mesmo grupo de processos que o processo atual ( ps -o pgid= )). Isso detectará qualquer outro processo iniciado no mesmo grupo de processos, mas, ao contrário, perderá o neto se ele for executado em seu próprio grupo de processos devido a uma chamada para setpgid ou setpgrp no filho ou no neto, que os daemons fazem. / p>

Você pode procurar processos no mesmo ID de sessão que o processo atual ( ps -o sid= )). Isso detectará qualquer outro processo iniciado dentro do mesmo ID de sessão, mas, ao contrário, perderá o neto se ele for executado em sua própria sessão devido a uma chamada para setsid no filho ou no neto, que os daemons fazem.

Você pode abrir um arquivo temporário e procurar por processos que tenham esse arquivo aberto ('fuser' $ tmpfile "). Isso é mais confiável porque ele só captura os processos iniciados a partir da parte do processo mestre que tinha esse arquivo aberto, ele não detectará quaisquer outros componentes do processo mestre. No entanto, como outras soluções, o neto perderá se ele ou o filho intermediário fechar os descritores de arquivos que não utilizou, o que os daemons fazem.

A maioria dos daemons tem uma opção de linha de comando para permanecer em primeiro plano. Você pode então executar daemon --foreground & daemon_pid=$! , e cabe a você tomar precauções para evitar que o daemon seja pego na saída da sessão ( nohup daemon --foreground </dev/null >daemon.log 2>&1 & é um bom começo).

    
por 21.10.2015 / 21:03
1

Você pode obter algumas informações usando strace no script, mas não mantenha sua strace em execução até que os subcomandos sejam concluídos. Por exemplo,

$ strace -b execve -e trace=none -e signal=none -f my-app
Process 21697 attached             <-- is the () &
[pid 21696] +++ exited with 0 +++  <-- is my-app ending
Process 21698 attached             <-- is the sleep 10
Process 21698 detached
test
Process 21702 attached             <-- is the sleep 5
Process 21702 detached
+++ exited with 0 +++

então temos os pids da sub-shell, e os comandos são executados lá, assumindo echo é um shell embutido, portanto, não é rastreado. -b execve é desanexar em exec, -f a seguir children, o -e reduz a saída ao não rastrear nada.

    
por 21.10.2015 / 18:44

Tags