Linux

Как получить информацию о только что запущенном процессе

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

myCommand

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

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

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

myCommand &

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

echo $!

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

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

 

Ответ 1

Вы можете использовать sh -c и exec, чтобы получить PID команды еще до ее выполнения.

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

sh -c 'echo $$; exec myCommand'.

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

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

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

В этом ответе приведен пример этой техники.

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

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

  1. После того как оболочка стала myCommand, нет оболочки, ожидающей выполнения последующих команд. sh -c 'echo $$; exec myCommand; foo не сможет попытаться запустить foo после замены себя на myCommand. Если вы не пишете сценарий, который выполняет эту команду как последнюю, вы не можете просто использовать echo $$; exec myCommand в оболочке, где выполняются другие команды.

  2. Вы не можете использовать для этого вложенную оболочку. (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, если это то, что вам нужно.

 

Ответ 2

Заверните команду в небольшой скрипт:

#!/bin/bash

ваша команда &

echo $! >/path/to/pid.file

 


Ответ 3

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

предположим, у вас есть скрипт с именем "forever.sh", который вы хотите запустить с args p1,p2,p3.

forever.sh исходный код:

#!/bin/sh

while [ 1 -lt 2 ] ; do

    logger "$0 запущен с параметрами \"$@\""

    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 не делает ничего, кроме записи строки в syslog каждые 5 секунд.

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

cat /var/run/forever.sh.pid 

5780

и forever.sh запущен. 

syslog grep:

Nov 24 16:07:17 pinkpony cia: ./forever.sh запущен с параметрами "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

 

Ответ 4

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

Это, например, не сработает:

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

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

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

 

Ответ 5

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

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

 

Схожие статьи

Linux

Защита Linux-серверов: iptables против fail2ban

Linux

Как узнать, взломан ли мой Linux-сервер?

Linux

Как работают макросы likely/unlikely в ядре Linux и в чем их преимущество

Linux

Атомарные изменения при доступе к каталогу, используя rsync

×