Как запустить процесс в приостановленном состоянии под Linux?

19

Практически мне нужен процесс, который ведет себя так, как будто я нажал Ctrl+Zсразу после его запуска.

Надеюсь, это можно сделать с помощью сценария оболочки.

(Кроме того, было бы неплохо знать полученный PID, поэтому я мог бы продолжить процесс позже.)

java.is.for.desktop
источник

Ответы:

7

После запуска процесса вы можете отправить его SIGSTOP, чтобы приостановить его. Чтобы возобновить его, отправьте SIGCONT. Я думаю, что этот маленький сценарий может помочь вам

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

Он запускает процесс (команда send в качестве параметра), приостанавливает его, печатает идентификатор процесса и ожидает его завершения.

radious
источник
1
Я изменил его, чтобы продолжить в конце: [введите] #!/bin/bash [введите] $@ & [введите] PID=$! [введите] kill -STOP $PID [введите] echo "Suspended: $PID, press ENTER to continue it" [введите] read [введите] kill -CONT $PID [введите] wait $PID [введите]echo
java.is.for.desktop
7
Точно так же вы знаете, что подпроцесс может завершиться еще до того, как у вас появится возможность отправить ему сигнал STOP.
MikeyB
16
Еще один день на гонках.
Ctrl-Alt-Delor
23

Из какой среды вы создаете процесс?

Если вы делаете это из среды, такой как код на C, вы можете выполнить fork (), а затем в дочерней среде отправить SIGSTOP себе перед exec (), предотвращая дальнейшее выполнение.

Более общим решением (вероятно, лучшим) будет создание заглушки, которая делает это. Таким образом, программа-заглушка будет:

  • Возьмите аргументы, состоящие из реального имени программы и аргументов
  • отправь SIGSTOP себе
  • exec () реальная программа с соответствующими аргументами

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


Пример для оболочки:

#!/bin/bash
kill -STOP $$
exec "$@"

И используя вышеуказанный кодез:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

jobs -lПоказывает PID. Но если вы делаете это из оболочки, вам не нужен PID напрямую. Вы можете просто сделать: kill -CONT %1(при условии, что у вас есть только одна работа).

Делать это с более чем одной работой? Оставлено как упражнение для читателя :)

MikeyB
источник
Я надеялся сделать это из сценария оболочки ...
java.is.for.desktop
Отлично, так как вы хотите сделать это из сценария оболочки, используйте программу-заглушку.
MikeyB
20

MikeyB ответ правильный. Из этого вопроса о суперпользователе, вот более краткая версия:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Чтобы понять это, нужно понять, как процессы запускаются в Unix: execсистемный вызов заменяет текущую запущенную программу новой , сохраняя существующий PID. Таким образом, способ создания независимого процесса состоит в том, чтобы сначала fork, а затем execзаменить работающую программу в дочернем процессе желаемой программой.

Ингредиенты этой команды оболочки:

  1. Скобки (...)запускают вложенную оболочку: еще один экземпляр BASH.
  2. Команда killотправляет сигнал STOP этому процессу, который переводит его в состояние ожидания.
  3. Как только вы разрешите продолжить процесс (отправив ему CONTсигнал), execкоманда заставит его заменить себя желаемой программой. my_commandсохраняет исходный PID суб-оболочки.
  4. Вы можете использовать $!переменную, чтобы получить PID процесса.
nibot
источник
2
Мне нравится этот, так как он принципиально правильный (просто то, что мне пришлось использовать -s STOPвместо -SIGSTOP). Все еще удивляетесь: почему это должно быть $BASHPIDвместо $$? (Я не очень понимаю разницу).
Hibou57
1
Для $$vs $BASHPIDя проверяю, что последний - это PID вложенной оболочки, а не первый. Есть забавная проблема: применение подсказки в bash-скрипте, чаще всего, приводит к сбою, и мне приходится делать что-то вроде этого: PID=$!; ps -p $PID; kill -s CONT $PID;… он терпит неудачу, если я удаляю ps -p $PIDдеталь: процесс исчезает (убивается?) Без сообщения об ошибке где-либо , Все нормально с интерактивной оболочки, проблема только в скрипте. Это слишком загадочно.
Hibou57
Я пытался использовать это решение для перечисления файловых дескрипторов my_command. ( goo.gl/cNbUE8 ), но дескрипторы все те же, что и my_command.
rasty.g
Варианты замены $BASHPIDдля оболочек, отличных от bash, см. Здесь
Якоб