Eu quero iniciar o processo (por exemplo, myCommand) e obter seu pid (para permitir matá-lo mais tarde).
Tentei ps e filtro por 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 esse 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.
O que pode ser mais simples do que
echo $!
? Como uma linha:Você pode usar
sh -c
eexec
para obter o PID do comando antes mesmo de ser executado.Para iniciar
myCommand
, para que seu PID seja impresso antes de iniciar a execução, você pode usar:Como funciona:
Isso inicia um novo shell, imprime o PID desse shell e, em seguida, usa o
exec
built-in para substituir o shell pelo seu comando, garantindo que ele tenha o mesmo PID. Quando seu shell executa um comando com oexec
builtin, seu shell está realmente se tornando esse comando , em vez do comportamento mais comum de bifurcar uma nova cópia de si mesmo, que tem seu próprio PID separado e que se torna o comando.Acho isso muito mais simples do que as alternativas que envolvem execução assíncrona (com
&
), controle de trabalho ou pesquisa comps
. Essas abordagens são boas, mas a menos que você tenha um motivo específico para usá-las - por exemplo, talvez o comando já esteja em execução, caso em que procurar seu PID ou usar o controle de tarefas faria sentido - sugiro considerar essa maneira primeiro. (E eu certamente não consideraria escrever um script complexo ou outro programa para conseguir isso).Esta resposta inclui um exemplo dessa técnica.
Partes desse comando podem ocasionalmente ser omitidas, mas geralmente não.
Mesmo que o shell que você está usando seja do estilo Bourne e, portanto, suporte o
exec
built-in com essas semânticas, você geralmente não deve tentar evitar o usosh -c
(ou equivalente) para criar um novo processo de shell separado para essa finalidade, porque:myCommand
, não há shell esperando para executar comandos subsequentes.sh -c 'echo $$; exec myCommand; foo
não seria capaz de tentar executarfoo
depois de se substituir pormyCommand
. A menos que você esteja escrevendo um script que execute isso como seu último comando, você não pode simplesmente usarecho $$; exec myCommand
em um shell onde você está executando outros comandos.(echo $$; exec myCommand)
pode ser sintaticamente melhor quesh -c 'echo $$; exec myCommand'
, mas quando você executa$$
dentro(
)
de , ele fornece o PID do shell pai, não do próprio subshell. 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ê pode usar para isso. Em particular, no Bash 4 ,(echo $BASHPID; exec myCommand)
funciona.Finalmente, observe que alguns shells realizarão uma otimização onde eles executam um comando como se por
exec
(ou seja, eles renunciam primeiro à bifurcação) quando se sabe que o shell não precisará fazer nada depois. Alguns shells tentam fazer isso sempre que é o último comando a ser executado, enquanto outros só o fazem quando não há outros comandos antes ou depois do comando, e outros não o fazem. O efeito é que, se você esquecer de escreverexec
e apenas usarsh -c 'echo $$; myCommand'
, às vezes ele fornecerá o PID correto em alguns sistemas com alguns shells. Eu recomendo nunca confiar em tal comportamento e, em vez disso, sempre incluirexec
quando é isso que você precisa.Envolva o comando em um pequeno script
Não conheço nenhuma solução mais simples, mas não está usando $! bom o bastante? Você sempre pode atribuir o valor a alguma outra variável se precisar mais tarde, como dito por outros.
Como uma nota lateral, em vez de canalizar de ps, você pode usar
pgrep
oupidof
.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 para sempre.sh:
crie um reaper.sh:
execute forever.sh através de reaper.sh:
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
e o forever.sh está rodando ok. syslog grep:
você pode ver na tabela de processos:
No shell bash, uma alternativa
$!
pode ser ojobs -p
built-in. Em alguns casos, o!
in$!
é interpretado pelo shell antes (ou no lugar) da expansão da variável, levando a resultados inesperados.Isso, por exemplo, não funcionará:
enquanto isso irá:
Você pode usar algo como:
Ou
Os dois comandos podem ser articulações usando
;
ou&&
. No segundo caso, o pid será definido somente se o primeiro comando for bem-sucedido. Você pode obter o ID do processo de$pid
.Esta é uma resposta um pouco hack-y e provavelmente não funcionará para a maioria das pessoas. Também é um grande risco de segurança, eu acho, então não faça isso a menos que você tenha certeza de que estará seguro e as entradas sã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 ...
Para encurtar a história, isso imprimirá o PID para
stdout
, depois carregará seu programa no processo. Ele ainda deve ter o mesmo PID.