Eu quero iniciar o processo (por exemplo, myCommand) e obter o seu pid (para permitir matá-lo mais tarde).
Eu tentei ps e filtrar por nome, mas não consigo distinguir processo por nomes
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Porque nomes de processos não são exclusivos.
Eu posso executar o processo por:
myCommand &
Descobri que posso obter esse PID:
echo $!
Existe alguma solução mais simples?
Eu ficaria feliz em executar o myCommand e obter seu PID como resultado de um comando de linha.
myprogram
teria sido incríveis&
como linha anterior; caso contrário, o eco retornará basicamente em branco.command & echo $!
congela a execução nesta etapa :(Embrulhe o comando em um pequeno script
fonte
Você pode usar
sh -c
eexec
obter o PID do comando antes mesmo de ele ser executado.Para começar
myCommand
, para que seu PID seja impresso antes de começar a ser executado, 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
built-in, seu shell está realmente se tornando esse comando , em vez do comportamento mais comum de criar uma nova cópia de si mesmo, que possui seu próprio PID separado e que se torna o comando.Acho que isso é muito mais simples do que as alternativas que envolvem execução assíncrona (com
&
), controle de tarefas 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; nesse caso, procurar por seu PID ou usar o controle de tarefas faria sentido - sugiro considerar isso 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 não geralmente.
Mesmo que o shell que você está usando seja do estilo Bourne e, portanto, ofereça suporte ao
exec
incorporado com essas semânticas, geralmente você não deve evitar o usosh -c
(ou equivalente) para criar um novo processo de shell separado para esse fim, porque:myCommand
, não há shell esperando para executar comandos subseqüentes.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 em que esteja executando outros comandos.(echo $$; exec myCommand)
pode ser sintaticamente melhor do quesh -c 'echo $$; exec myCommand'
, mas quando você executa o$$
interior(
)
, ele fornece o PID do shell pai, não do subshell 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 localizar o PID do subshell, que você pode usar para isso. Em particular, no Bash 4 ,(echo $BASHPID; exec myCommand)
funciona.Por fim, observe que alguns shells executam uma otimização onde executam um comando como se fossem
exec
(ou seja, renunciam primeiro à bifurcação) quando se sabe que o shell não precisará fazer nada posteriormente. Alguns shells tentam fazer isso a qualquer momento, sendo o último comando a ser executado, enquanto outros o fazem apenas 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 usarsh -c 'echo $$; myCommand'
, ele às vezes fornecerá o PID correto em alguns sistemas com alguns shells. Eu recomendo que nunca confie em tal comportamento e, em vez disso, sempre incluaexec
quando é isso que você precisa.fonte
myCommand
, preciso definir várias variáveis de ambiente no meu script bash. Elas serão transferidas para o ambiente em que oexec
comando está sendo executado?exec
comando. No entanto, essa abordagem não funciona quandomyCommand
inicia outros processos, com os quais você precisa trabalhar; quando emito umkill -INT <pid>
ondepid
foi obtido dessa maneira, o sinal não alcança os subprocessos iniciados pormyCommand
, enquanto que se eu executarmyCommand
na sessão atual e Ctrl + C, os sinais se propagam corretamente.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
Não conheço 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 uma observação lateral, em vez de usar o ps do ps, você pode usar
pgrep
orpidof
.fonte
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 forever.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 forever.sh está funcionando bem. syslog grep:
você pode vê-lo na tabela de processos:
fonte
exec "$@"
vez deexec $*
. Tecnicamente, o que você precisa preservar não é o espaço em branco, mas as ocorrências dos caracteres no parâmetro do shell do IFS (o padrão é espaço, tabulação e nova linha).No shell bash, uma alternativa ao
$!
pode ser ojobs -p
built-in. Em alguns casos, o!
in$!
é interpretado pelo shell antes (ou em vez de) da expansão da variável, levando a resultados inesperados.Isso, por exemplo, não funcionará:
enquanto isso irá:
fonte
Você pode usar algo como:
Ou
Os dois comandos podem ser articulaçõ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$pid
.fonte
$!
após&&
ou;
nunca fornecerá o PID do processo iniciado para o lado esquerdo do separador de comandos.$!
é definido apenas para processos iniciados de forma assíncrona (por exemplo, geralmente com&
mas alguns shells também possuem outros métodos).Esta é uma resposta um tanto quanto improvável e provavelmente não funcionará para a maioria das pessoas. Também é um risco enorme para a segurança, então não faça isso, a menos que você tenha certeza de que estará seguro e que 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) e execute o programa como./start your-program-here arg0 arg1 arg2 ...
Para encurtar a história, isso imprimirá o PID e
stdout
, em seguida, carregará seu programa no processo. Ainda deve ter o mesmo PID.fonte
stdout
não parece estar registrada neste exemplo:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS