Bash: получение PID для демонизированного сеанса экрана

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

Я запускаю экран с screen -dmS screenname,

Как мне получить PID экрана прямо до или сразу после начала сеанса экрана?

6 ответов

Решение

Это показывает PID для экрана с именем nameofscreen:

$ screen -ls
There are screens on:
    19898.otherscreen   (07/03/2012 05:50:45 PM)    (Detached)
    19841.nameofscreen  (07/03/2012 05:50:23 PM)    (Detached)
2 Sockets in /var/run/screen/S-sarnold.

$ screen -ls | awk '/\.nameofscreen\t/ {print strtonum($1)}'
19841
$ 

Ты можешь использовать:

screen -DmS nameofscreen

который не разветвляет процесс демона, позволяющий вам узнать pid.

Анализ выходных данных screen -ls может быть ненадежным, если два сеанса экрана были запущены с одним и тем же именем. Другой подход состоит в том, чтобы не допустить, чтобы сеанс экрана запустил процесс и поместил его в фоновом режиме:

Например, с существующим начальным сеансом экрана:

fess@hostname-1065% screen -ls
There is a screen on:
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

создайте экран, используя -D -m вместо -d -m, который не разворачивает новый процесс. Положите его в фоновом режиме и получите его pid. (Использование семантики оболочки posix)

fess@hostname-1066% screen -DmS nameofscreen & 
[3] 19431
fess@hostname-1067% pid=$! 

Теперь есть два экрана с одинаковым именем:

fess@hostname-1068% screen -ls
There are screens on:
        19431.nameofscreen    (01/15/2013 10:53:31 AM)        (Detached)
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

но мы знаем разницу:

fess@hostname-1069% echo $pid
19431

и мы можем точно попросить его выйти:

fess@hostname-1070% screen -S $pid.nameofscreen -X quit
[3]  - done       screen -DmS nameofscreen

теперь опять только оригинал:

fess@hostname-1071% screen -ls 
There is a screen on:
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

Вы можете получить PID сеансов экрана вот так:

$ screen -ls
There are screens on:
        1934.foo_Server         (01/25/15 15:26:01)     (Detached)
        1876.foo_Webserver      (01/25/15 15:25:37)     (Detached)
        1814.foo_Monitor        (01/25/15 15:25:13)     (Detached)
3 Sockets in /var/run/screen/S-ubuntu.

Допустим, вы хотите, чтобы PID программы, запущенной в Bash, находился в foo_Monitor сеанс экрана. Используйте PID foo_Monitor сеанс экрана, чтобы получить PID bash сеанс выполняется в нем путем поиска PPID (PID Parent) для известного PID:

$ ps -el | grep 1814 | grep bash
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  1815  1814  0  80   0 -  5520 wait   pts/1    00:00:00 bash

Теперь получите только PID bash сессия:

$ ps -el | grep 1814 | grep bash | awk '{print $4}'
1815

Теперь мы хотим, чтобы процесс с этим PID. Просто вложите команды, и на этот раз используйте -v флаг на grep bash чтобы получить процесс, который не bash:

echo $(ps -el | grep $(ps -el | grep 1814 | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')
23869

Просто замените 1814 реальным PID или сеансом экрана:

echo $(ps -el | grep $(ps -el | grep SCREEN_SESSION_PID | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')

Этот ответ вдохновлен @sarnold.

Позвольте мне добавить способ получить все PID экрана:

screen -ls | awk '/[0-9]{1,}\./ {print strtonum($1)}'

Поскольку 0-299 - это PID демона в старом ядре, вы можете изменить {1,} на {3,}

Вы можете работать с каждым процессом следующими способами, например выходить из них.

pidList=(screen -ls | awk '/[0-9]{3,}\./ {print strtonum($1)}')
for pid in ${pidList[@]};
do
    screen -X -S $pid quit
done

Вы также можете сделать некоторые другие вещи с screen -X -S $pid stuff 'command\n',

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

Вы можете использовать pgrep, чтобы найти процесс, PPID которого является PID экрана. Или сделать что-то вроде этого:

rm mypidfile
screen -dmS blah sh -c 'echo $$ > mypidfile ; exec sh'
# the write to mypidfile is happening in the background, so wait it to show up
while [ ! -s mypidfile ]; do sleep 1; done
pid=`cat mypidfile`
# $pid is now the PID of the shell that was exec'ed inside screen

Чтобы завершить ответ Сарнольда:

$ screen -ls
There are screens on:
    19898.otherscreen   (07/03/2012 05:50:45 PM)    (Detached)
    19841.nameofscreen  (07/03/2012 05:50:23 PM)    (Detached)
2 Sockets in /var/run/screen/S-sarnold.

$ screen -ls | awk '/\.nameofscreen\t/ {print strtonum($1)}'
19841

... получить PID процессов с этим PID в качестве PPID следующим образом:

$ ps --ppid 19841 -o pid=
19842

Первый ответ у меня не сработал. Вместо этого я использовал это:

screen -ls | grep -oE "[0-9]+\.screen_name" | sed -e "s/\..*$//g"

grep -oE возвращает только то, что соответствует регулярному выражению, которое соответствует как минимум 1 числу, буквальной точке, а затем screen_name. Например, это может выводить784.screen_name(если pid был 784). Затем используйте sed, чтобы удалить все, что находится после первой точки в конце строки.

Другой способ - использовать параметр экрана -Q для запроса сеанса:

screen -S nameofscreen -Q echo '$PID'

Обратите внимание, что это также будет отображать PID внутри сеанса экрана в качестве уведомления.

Другие вопросы по тегам