Отримайте PID будь-якої команди у фоновій послідовності команд


10

Якщо в bash, я виконую:

cmd1 | cmd2 | ... | cmdi | ... | cmdn &

де cmd{1..n}може не відрізнятись, як отримати ПІД cmdi? Як варіант я можу сигналізувати про cmdiпроцес? (Наприклад, відправити його SIGUSR1?) pkill/ pgrep, І pidofтак далі не схожі на хороші відповіді, так як інших випадках , cmdiможливо , працює, в тому числі в рамках одного і того ж трубопроводу. jobs -pдає ПІД cmd1для мене.

iможе бути чим завгодно {1..n}.



1
@ G-Man Care пояснити? Я бачу лише поверхневу схожість, і як я пояснив у відповіді Рамеша, зміна набору команд не приносить великої користі.
muru

Поверхнева схожість? cat /var/run/out | nc -l 8080лише поверхнево схожий на cmd1 | cmd2? Ваше обмеження в тому, що ви хочете набрати трубопровід з голими кістками, а потім відновити PID, (1) не вказано у питанні, і (2) навряд чи дозволить отримати хороше загальне рішення.
G-Man

@ G-Man Навпаки, ви накладаєте обмеження, прості не вказані. cmd1 | cmd2це дуже особливий випадок, коли обидва PID легко отримати. Я щось сказав про російську? То чому б ви припускали n = 2? Я щось казав про те, що таке cmdi? То чому ви вважаєте, що я можу змінити cmdi? Я прошу загального рішення, і ви накладаєте обмеження.
muru

Відповіді:


6

Для оригінальної версії питання, коли потрібен лише PID останньої команди, спеціальна змінна $!є ідеальною.

foo | bar | baz &
baz_pid=$!

Немає подібного простого доступу до PID інших процесів.

Довго пройшло багато часу, щоб $pipestatus(zsh) та $PIPESTATUS(bash) були додані, нарешті, давши нам доступ до всіх статусів виходу в трубопроводі, на додаток до $?останнього, який існував з часів оригінальної оболонки Борна. Можливо, щось подібне відбудеться з $!часом.


Не заперечуєте, якби я відредагував питання, щоб також запитати PID довільної команди у списку? Або я повинен почати нове запитання?
muru

Ймовірно, вам доведеться чекати набагато довше, щоб відповісти на це. У мене немає сильних почуттів щодо організації сайту stackexchange, тому окреме питання, редагувати питання, що завгодно ... не буде мене турбувати

Це добре, негайна проблема вирішена, зараз цікавість керована. Я тоді його відредагую. Лише голова, оскільки я бачив, що питання різко змінюються, і старі відповіді виглядають дуже нецікаво.
muru

@muru - зауважте, що краще було б зробити це новий Q, посилаючись на цей.
slm

@slm належним чином зауважив. Зробимо це в майбутньому.
муру

4

Я думаю, ви могли б зробити щось, як тут запропоновано .

(ls -l | echo "Hello" | df -h & echo $! >&3 ) 3>pid

Тут у наведеному вище прикладі я отримав pid третього конвеєрного процесу та відзначив його до файла pid. Я можу це зафіксувати для будь-якого трубного процесу.


Цікаво, але це передбачало б зміну набору команд. Мало використовувати, як тільки команди були виконані.
muru

@muru - що? Яке використання має будь-який PID після його завершення? Ви хочете PID трубопроводу? jobs -p. сигналізуйте це за допомогою SIGPIPE. Хочеш cmdi- це.
mikeserv

1
@mikeserv Якщо вони не знаходяться на задньому плані, вони працюють, як ми говоримо. Якою чарівницею я повинен змінити командний рядок для цього?
муру

1
@muru, що було б чаклунством. вам потрібен налагоджувач.
mikeserv

Я вважаю, що це є корисною схемою для запуску фонових процесів, очікування, коли вони досягнуть певного стану, а потім їх вбивства. Якщо когось цікавить: gist.github.com/MatrixManAtYrService/…
MatrixManAtYrService

2

Не дуже портативним, специфічним для Linux рішенням може бути відстеження процесів за допомогою труб, які їх з'єднують. Ми можемо отримати PID першої ( jobs -p) та останньої ( $!) команд у конвеєрі. Використовуючи будь-який PID, цей сценарій може зробити цю роботу:

#! /bin/bash

PROC=$1
echo $PROC

if [[ $(readlink /proc/$PROC/fd/1) =~ ^pipe: ]]
then
    # Assuming first process in chain...
    NEXT_FD=1
elif [[ $(readlink /proc/$PROC/fd/0) =~ ^pipe: ]]
then
    # Last process in chain...
    NEXT_FD=0
else
    # Doesn't look like a pipe.
    exit
fi

NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)

while [[ $NEXT_PROC_PIPE =~ ^pipe: ]] 
do
    PROC=$(find /proc/*/fd -type l -printf "%p/%l\n" 2>/dev/null | awk -F'/' '($6 == "'"$NEXT_PROC_PIPE"'") && ($3 != "'$PROC'" ) {print $3}')
    NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)
    echo $PROC
done

Для допитливих тут про щось подібне
MatrixManAtYrService
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.