Como obter o pid do processo recém-iniciado

55

Eu quero iniciar o processo (por exemplo, myCommand) e obter seu pid (para permitir matá-lo mais tarde).

Eu tentei ps e filtrar pelo nome, mas não consigo distinguir processo por nomes

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

Porque os nomes dos processos não são exclusivos.

Eu posso executar o processo por:

myCommand &

Descobri que posso obter este PID por:

echo $!

Existe alguma solução mais simples?

Eu ficaria feliz em executar myCommand e obter seu PID como resultado de um comando de linha.

    
por rafalmag 24.11.2010 / 09:28

8 respostas

64

O que pode ser mais simples que echo $! ? Como uma linha:

myCommand & echo $!
    
por 24.11.2010 / 09:46
22

Quebra o comando em um pequeno script

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
    
por 24.11.2010 / 09:53
8

Você pode usar sh -c e exec para obter o PID do comando mesmo antes ser executado.

Para iniciar myCommand , para que seu PID seja impresso antes de começar a ser executado, você pode usar:

sh -c 'echo $$; exec myCommand'

Como funciona:

Isso inicia um novo shell, imprime o PID desse shell e, em seguida, usa o exec embutido para substituir o shell pelo seu comando, garantindo que ele tenha o mesmo PID. Quando seu shell executa um comando com o exec builtin, seu shell é na verdade tornando-se esse comando , em vez de o comportamento mais comum de bifurcar um novo cópia de si mesmo, que tem seu próprio PID separado e que então se torna o comando.

Acho isso muito mais simples do que alternativas envolvendo execução assíncrona (com & ), controle de tarefa ou pesquisa com ps . Essas abordagens são boas, mas, a menos que você tenha uma razão específica para usá-las - por exemplo, talvez o comando já esteja em execução; nesse caso, procurar por seu PID ou usar o controle de tarefas faria sentido - sugiro considerá-lo primeiro. (E eu certamente não consideraria escrever um script complexo ou outro programa para conseguir isso).

Esta resposta inclui um exemplo desta técnica.

Partes desse comando podem ocasionalmente ser omitidas, mas normalmente não.

Mesmo que o shell que você está usando seja do tipo Bourne e, portanto, suporte o exec integrado a essas semânticas, geralmente você não deve tentar usar sh -c (ou equivalente) para criar um novo < em> separado processo shell para este fim, porque:

  • Quando o shell se tornar myCommand , não haverá shell aguardando para executar comandos subsequentes. sh -c 'echo $$; exec myCommand; foo não poderá tentar executar foo depois de se substituir por myCommand . A menos que você esteja escrevendo um script que execute isso como seu último comando, você não pode simplesmente usar echo $$; exec myCommand em um shell no qual você está executando outros comandos.
  • Você não pode usar um subshell para isso. (echo $$; exec myCommand) pode ser sintaticamente mais agradável que sh -c 'echo $$; exec myCommand' , mas quando você executa $$ dentro de ( ) , ele fornece o PID do shell pai, não da sub-shell em si. Mas é o PID do subshell que será o PID do novo comando. Alguns shells fornecem seus próprios mecanismos não portáteis para encontrar o PID do subshell, que você poderia usar para isso. Em particular, no Bash 4 , (echo $BASHPID; exec myCommand) funciona.

Finalmente, observe que alguns shells executam uma otimização na qual eles executam um comando como se fossem exec (isto é, eles renunciaram a forjar primeiro) quando se sabe que a casca não precisará fazer nada depois. Algumas shells tentam fazer isso sempre que for o último comando a ser executado, enquanto outras só farão isso quando não houver outros comandos antes ou depois do comando, e outros não o farão. O efeito é que se você esquecer de escrever exec e apenas usar sh -c 'echo $$; myCommand' , então algumas vezes dará a você o PID certo em alguns sistemas com algum conchas. Eu não recomendo nunca confiar em tal comportamento , e em vez disso, sempre incluindo exec quando é isso que você precisa.

    
por 20.03.2018 / 17:58
7

Eu não sei de nenhuma solução mais simples, mas não estou usando $! bom o bastante? Você sempre pode atribuir o valor a alguma outra variável se precisar mais tarde, como dito por outras pessoas.

Como nota lateral, em vez de canalizar do ps, você pode usar pgrep ou pidof .

    
por 24.11.2010 / 09:48
5

use exec de um script bash depois de registrar o pid em um arquivo:

exemplo:

suponha que você tenha um script chamado "forever.sh" que deseja executar com args p1, p2, p3

código fonte sour.sh:

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "$0 running with parameters \"$@\""
    sleep 5
done

crie um reaper.sh:

#!/bin/sh

echo $$ > /var/run/$1.pid
exec "$@"

execute forever.sh por meio de reaper.sh:

./reaper.sh ./forever.sh p1 p2 p3 p4 &

forever.sh não faz nada além de registrar uma linha no syslog a cada 5 segundos

agora você tem o pid em /var/run/forever.sh.pid

cat /var/run/forever.sh.pid 
5780

e o forever.sh está sendo executado. syslog grep:

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"

você pode vê-lo na tabela de processos:

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4
    
por 24.11.2010 / 15:13
3

No bash shell, uma alternativa para $! pode ser o jobs -p integrado. Em alguns casos, o ! em $! é interpretado pelo shell antes (ou em vez de) da expansão da variável, levando a resultados inesperados.

Isso, por exemplo, não funciona:

((yourcommand) & echo $! >/var/run/pidfile)

enquanto isso:

((yourcommand) & jobs -p >/var/run/pidfile)
    
por 19.07.2017 / 19:02
1

Você pode usar algo como:

$ myCommand ; pid=$!

Ou

$ myCommand && pid=$!

Os dois comandos podem ser junções usando ; ou && . No segundo caso, o pid será definido apenas se o primeiro comando for bem-sucedido. Você pode obter o ID do processo em $pid .

    
por 24.11.2010 / 09:46
1

Esta é uma resposta de hack e provavelmente não funcionará para a maioria das pessoas. Também é um enorme risco de segurança, por isso não faça a menos que tenha certeza de que você estará seguro e as entradas estão higienizadas e ... bem, você entendeu.

Compile o pequeno programa C aqui em um binário chamado start (ou o que você quiser), então execute seu programa como ./start your-program-here arg0 arg1 arg2 ...

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc >= 2)
    {
        printf("%lu\n", (long unsigned) getpid());
        if (execvp(argv[1], &argv[1]) < 0)
        {
            perror(NULL);
            return 127;
        }
    }
    return 0;
}

Para encurtar a história, isso imprimirá o PID para stdout e, em seguida, carregará seu programa no processo. Deve ainda ter o mesmo PID.

    
por 27.07.2016 / 00:52