Вопрос: Как получить pid только что начатого процесса


Я хочу начать процесс (например, myCommand) и получить его pid (чтобы разрешить его позже).

Я пробовал ps и фильтровал по имени, но я не могу отличить процесс по именам

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

Поскольку имена процессов не уникальны.

Я могу запустить процесс:

myCommand &

Я обнаружил, что могу получить этот PID:

echo $!

Есть ли более простое решение?

Я был бы счастлив выполнить myCommand и получить его PID в результате одной командной строки.


47
2017-11-24 08:28


Источник




Ответы:


Что может быть проще, чем echo $!? Как одна строка:

myCommand & echo $!

58
2017-11-24 08:46



Спасибо, что слияние этих команд с «&» мне очень помогло. - rafalmag
в сценарии bash, в цикле, который запускает программы, $! неточно. Иногда он возвращает pid самого скрипта, иногда grep или awk запускает из скрипта любое решение, чтобы специально получить pid процесса, только что запущенного в этом сценарии? что-то вроде pid =myprogram было бы здорово
Обратите внимание, что для этого вам необходимо запустить команду, используя &как предыдущая строка, в противном случае эхо в основном возвращает пустое. - rogerdpack
присвоение переменной command & echo $! замораживает выполнение на этом этапе :( - Shashank Vivek
это спасает мою жизнь! Благодарю. - temple


Оберните команду небольшим скриптом

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file

20
2017-11-24 08:48





Я не знаю более простого решения, но не использую $! достаточно хорошо? Вы всегда можете присвоить значение какой-либо другой переменной, если вам это нужно позже, как говорят другие.

В качестве побочного примечания, вместо того, чтобы прокладывать трубы из ps, вы можете использовать pgrep или pidof,


7
2017-11-24 14:13





используйте exec из сценария bash после регистрации pid в файл:

пример:

предположим, что у вас есть сценарий с именем «forever.sh», который вы хотите запустить с помощью args 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 "$@"

run forever.sh через reaper.sh:

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

forever.sh делает не более, чем протоколирование строки в syslog каждые 5 секунд

теперь у вас есть pid в /var/run/forever.sh.pid

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

и forever.sh работает aok. syslog 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

5
2018-03-20 16:58



oh и «oneliner»: / bin / sh -c 'echo $$> / tmp / my.pid && exec program args' & - user237419
Чтобы правильно сохранить внутренние пробелы в аргументах, вы должны использовать exec "$@" вместо exec $*, Технически то, что вам нужно сохранить, - это не пробел, а появление символов в параметре оболочки IFS (по умолчанию это пробел, табуляция и новая строка). - Chris Johnsen
Дело принято. :) - user237419
Спасибо, я не знал параметр $$. Это может быть очень полезно. - rafalmag


Вы можете использовать sh -c а также exec для получения ПИД-кода команды до он работает.

Начать myCommand, чтобы его PID был напечатан до того, как он начнет работать, вы можете использовать:

sh -c 'echo $$; exec myCommand'

Как это работает:

Это запускает новую оболочку, печатает PID этой оболочки, а затем использует exec встроенный замещать оболочку с вашей командой, гарантируя, что она имеет тот же PID. Когда ваша оболочка запускает команду с exec встроенный, ваша оболочка на самом деле становление эта команда, скорее, чем более распространенное поведение разворачивания новой копии самого себя, которая имеет свой отдельный PID и которая затем становится командой.

Я считаю, что это намного проще, чем альтернативы, включающие асинхронное выполнение (с &), управление заданиями или поиск с помощью ps, Эти подходы прекрасны, но если у вас нет конкретной причины их использовать, например, возможно, команда уже запущена, и в этом случае поиск его PID или использование управления заданиями будет иметь смысл - я предлагаю сначала рассмотреть этот путь. (И я бы не стал рассматривать сложный сценарий или другую программу для достижения этого).

Этот ответ включает пример этой методики.


Части этой команды иногда могут быть опущены, но не обычно.

Даже если оболочка, которую вы используете, является стилем Bourne и, таким образом, поддерживает exec в сочетании с этой семантикой, вы, как правило, не должны пытаться избегать использования sh -c (или эквивалент) для создания нового, отдельный для этой цели, потому что:

  • Как только оболочка стала 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 когда это то, что вам нужно.


5
2017-07-19 17:02



Прежде чем я смогу запустить myCommand, Мне нужно установить несколько переменных среды в моем сценарии bash. Будут ли они переноситься в среду, в которой exec команда запущена? - user5359531
Похоже, моя среда переносится в exec команда. Однако этот подход не работает, если myCommand запускает другие процессы, с которыми вам нужно работать; когда я выдаю kill -INT <pid> где pid был получен таким образом, сигнал не достигает подпроцессов, начатых myCommand, тогда как если я убегу myCommand  в текущей сессии и Ctrl + C сигналы распространяются правильно. - user5359531


В оболочке bash альтернатива $! может быть jobs -p встроенный. В некоторых случаях ! в $! интерпретируется оболочкой до (или вместо) расширения переменной, что приводит к неожиданным результатам.

Это, например, не будет работать:

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

в то время как это будет:

((yourcommand) & jobs -p >/var/run/pidfile)

2
2017-11-24 08:46



Я думаю, вы имели в виду ((ваша команда) & jobs -p> / var / run / pidfile). - Dom
@ DominicO'Brien, вы правы, конечно. Благодарю. - mustaccio


Вы можете использовать что-то вроде:

$ myCommand ; pid=$!

Или

$ myCommand && pid=$!

Две команды могут быть суставами, использующими ; или &&, Во втором случае pid будет установлен только в том случае, если первая команда выполнена успешно. Вы можете получить идентификатор процесса из $pid,


1
2017-07-26 22:52



OP хочет получить PID, чтобы он мог убить его позже. ; и && требуют, чтобы исходный процесс вышел до эха $! выполняется. - Iain
Да ты прав. Это даст вам pid после завершения myCommand. - Khaled
привязка $! после && или ; никогда не даст вам PID процесса, запущенного для левой части разделителя команд. $! устанавливается только для процессов, запущенных асинхронно (например, обычно с & но некоторые оболочки также имеют другие методы). - Chris Johnsen
это полезно, и почему никто не голосовал за меня? хорошая работа хотя :) - temple


Это немного хакерский ответ и вряд ли будет работать для большинства людей. Это также огромный риск для безопасности, поэтому не делайте этого, если вы не уверены, что будете в безопасности, а входные данные дезинфицированы и ... ну, вы поняли.

Скомпилируйте небольшую программу 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.


1