O que pode ser mais simples que echo $!
? Como uma linha:
myCommand & echo $!
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.
Quebra o comando em um pequeno script
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
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'
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.
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:
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. (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.
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
.
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
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)
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
.
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.