Я хочу запустить процесс (например, myCommand) и получить его pid (чтобы позже его можно было убить).
Я пробовал ps и фильтровать по имени, но не могу отличить процесс по именам
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Потому что имена процессов не уникальны.
Я могу запустить процесс:
myCommand &
Я обнаружил, что могу получить этот PID:
echo $!
Есть ли решение попроще?
Я был бы счастлив выполнить myCommand и получить его PID в результате одной строчной команды.
Что может быть проще echo $!
? Одной строкой:
myCommand & echo $!
sh -c
и exec
чтобы получить PID команды даже перед он бежит.Начать myCommand
, чтобы его PID был напечатан перед запуском, вы можете использовать:
sh -c 'echo $$; exec myCommand'
Это запускает новую оболочку, печатает PID этой оболочки, а затем использует exec
встроенный заменить оболочку с вашей командой, убедившись, что у нее тот же PID. Когда ваша оболочка запускает команду с exec
встроенный, ваша оболочка фактически становление эта команда, скорее, чем более распространенное поведение создания новой копии самой себя, которая имеет свой собственный отдельный PID и которая затем становится командой.
Я считаю, что это намного проще, чем альтернативы с асинхронным выполнением (с &
), управление вакансиями или поиск с помощью ps
. Эти подходы хороши, но если у вас нет конкретной причины их использовать - например, возможно, команда уже запущена, и в этом случае будет иметь смысл поиск ее PID или использование управления заданиями - я предлагаю сначала рассмотреть этот способ. (И я, конечно, не стал бы думать о написании сложного сценария или другой программы для достижения этой цели).
Этот ответ включает пример этой техники.
Даже если оболочка, которую вы используете, выполнена в стиле Борна и, таким образом, поддерживает exec
встроенные с этой семантикой, вам обычно не следует избегать использования sh -c
(или эквивалент) для создания нового, отдельный Shell процесс для этой цели, потому что:
myCommand
, нет оболочки, ожидающей выполнения последующих команд. sh -c 'echo $$; exec myCommand; foo
не сможет попытаться запустить foo
после замены себя на myCommand
. Если вы не пишете скрипт, который запускает это как последнюю команду, вы не можете просто использовать echo $$; exec myCommand
в оболочке, в которой вы выполняете другие команды.(echo $$; exec myCommand)
может быть синтаксически лучше, чем sh -c 'echo $$; exec myCommand'
, но когда ты бежишь $$
внутри (
)
, он дает PID родительской оболочки, а не самой подоболочки. Но PID подоболочки будет PID новой команды. Некоторые оболочки предоставляют свои собственные непереносимые механизмы для поиска PID подоболочки, который вы мог используйте для этого. В частности, в Bash 4, (echo $BASHPID; exec myCommand)
работает.Наконец, обратите внимание, что некоторые оболочки будут выполнять оптимизация где они запускают команду, как будто exec
(т.е. они сначала отказываются от разветвления), когда известно, что оболочке не нужно будет ничего делать после этого. Некоторые оболочки пытаются сделать это в любое время, когда это последняя команда, которая будет запущена, в то время как другие будут делать это только тогда, когда нет других команд до или после команды, а другие не будут делать это вообще. Эффект таков, что если вы забудете написать exec
и просто используйте sh -c 'echo $$; myCommand'
тогда это будет иногда дать вам правильный PID на некоторые системы с некоторые снаряды. Я рекомендую никогда не полагаться на такое поведение, и вместо этого всегда включая exec
когда это то, что вам нужно.
Оберните команду в небольшой скрипт
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Я не знаю более простого решения, но не использую $! достаточно хорошо? Вы всегда можете присвоить значение какой-либо другой переменной, если оно вам понадобится позже, как сказали другие.
В качестве примечания, вместо трубопроводов из ps вы можете использовать pgrep
или pidof
.
используйте exec из сценария bash после регистрации pid в файле:
пример:
предположим, у вас есть скрипт с именем forever.sh, который вы хотите запустить с аргументами p1, p2, p3
Исходный код forever.sh:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"$@\""
sleep 5
done
создайте reaper.sh:
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "$@"
запустить forever.sh через reaper.sh:
./reaper.sh ./forever.sh p1 p2 p3 p4 &
forever.sh не делает ничего, кроме записи строки в системный журнал каждые 5 секунд
теперь у вас есть pid в /var/run/forever.sh.pid
cat /var/run/forever.sh.pid
5780
и forever.sh работает aok. системный журнал grep:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
вы можете увидеть это в таблице процессов:
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
В оболочке bash альтернатива $!
может быть jobs -p
встроенный. В некоторых случаях !
в $!
интерпретируется оболочкой до (или вместо) расширения переменной, что приводит к неожиданным результатам.
Это, например, не сработает:
((yourcommand) & echo $! >/var/run/pidfile)
пока это будет:
((yourcommand) & jobs -p >/var/run/pidfile)
Вы можете использовать что-то вроде:
$ myCommand ; pid=$!
Или
$ myCommand && pid=$!
Две команды могут быть суставами, используя ;
или &&
. Во втором случае pid будет установлен только в случае успешного выполнения первой команды. Вы можете получить идентификатор процесса из $pid
.
Это немного хитрый ответ, который вряд ли сработает для большинства людей. Я думаю, это также огромный риск для безопасности, поэтому не делайте этого, если вы не уверены, что будете в безопасности, а входные данные продезинфицированы и ... ну, вы поняли.
Скомпилируйте небольшую программу на C в двоичный файл с именем start
(или как хотите), затем запустите свою программу как ./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;
}
Короче говоря, это напечатает PID для stdout
, а затем загрузите вашу программу в процесс. У него должен быть тот же PID.