it-roy-ru.com

Как я могу запустить новый процесс, который НЕ является дочерним по отношению к оригинальному процессу?

(OSX 10.7) Приложение, которое мы используем, позволяет нам назначать сценарии, которые будут вызываться, когда в приложении происходят определенные действия. Я назначил bash-скрипт, и он вызывается, проблема в том, что мне нужно выполнить несколько команд, подождать 30 секунд, а затем выполнить еще несколько команд. Если мой bash-скрипт выполняет «сон 30», все приложение останавливается на эти 30 секунд, ожидая завершения сценария.

Я попытался поместить 30-секундное ожидание (и второй набор команд) в отдельный скрипт и вызвать "./secondScript &", но приложение все еще находится там в течение 30 секунд, ничего не делая. Я предполагаю, что приложение ожидает завершения сценария и всех дочерних процессов .

Я пробовал эти варианты для вызова второго скрипта из основного скрипта, у них всех одна и та же проблема:

  • Nohup ./secondScript &
  • ((./secondScript &) &)
  • (./secondScript &)
  • Сценарий Nohup -q/dev/null secondScript &

У меня нет возможности изменить приложение и попросить его запустить мой сценарий, а не ждать его завершения.

Как я могу запустить процесс (я бы предпочел, чтобы процесс был на языке сценариев), чтобы новый процесс не был дочерним по отношению к текущему процессу?

Спасибо, Крис

постскриптум Я попробовал команду «отречься», и она тоже не помогла. Мой основной скрипт выглядит так:

[initial commands]
echo Launching second script
./secondScript &
echo Looking for jobs
jobs
echo Sleeping for 1 second
sleep 1
echo Calling disown
disown
echo Looking again for jobs
jobs
echo Main script complete

и что я получаю для вывода это:

Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete

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

p.p.s

Если в верхней части основного скрипта я выполняю «ps», единственное, что он возвращает, - это идентификатор процесса интерактивного сеанса bash, который я открыл в отдельном окне терминала.

Значение $ Shell равно/bin/bash

Если я выполню "ps -p $$", это правильно говорит мне

PID   TTY TIME    CMD
26884 ??  0:00.00 mainScript

Если я выполню «lsof -p $$», это даст мне всевозможные результаты (я не вставил здесь все столбцы, предполагая, что они не актуальны):

FD   TYPE   NAME
cwd  DIR    /private/tmp/blahblahblah
txt  REG    /bin/bash
txt  REG    /usr/lib/dyld
txt  REG    /private/var/db/dyld/dyld_shared_cache_x86_64
0    PIPE   
1    PIPE   -> 0xffff8041ea2d10
2    PIPE   -> 0xffff 8017d21cb
3r   DIR    /private/tmp/blahblah
4r   REG    /Volumes/DATA/blahblah
255r REG    /Volumes/DATA/blahblah
17
Betty Crokker

Типичный способ сделать это в Unix - это двойная вилка. В Bash вы можете сделать это с

( sleep 30 & )

(..) создает дочерний процесс, а & создает процесс внука. Когда дочерний процесс умирает, процесс внука наследуется init. 


Если это не работает, то ваше приложение не ожидает дочерних процессов. 

Другие вещи, которые он может ожидать, включают в себя сеанс и открытые файлы блокировки:

Для создания нового сеанса в Linux есть setsid. В OS X вы можете сделать это с помощью script, который также создает новый сеанс:

# Linux:
setsid sleep 30

# OS X:
Nohup script -q -c 'sleep 30' /dev/null &

Чтобы найти список унаследованных файловых дескрипторов, вы можете использовать lsof -p yourpid, который выведет что-то вроде:

sleep   22479 user    0u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    1u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    2u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    5w   REG  252,0        0  1048806 /tmp/lockfile

В этом случае, в дополнение к стандартным FD 0, 1 и 2, у вас также есть открытый fd 5 с файлом блокировки, который может ожидать родительский файл. 

Чтобы закрыть fd 5, вы можете использовать exec 5>&-. Если вы считаете, что файл блокировки может быть самим stdin/stdout/stderr, вы можете использовать Nohup, чтобы перенаправить их на что-то другое.

23
that other guy

Я думаю, это зависит от того, как ваш родительский процесс пытается определить, завершен ли ваш дочерний процесс . В моем случае (мой родительский процесс был gnu make), мне удается закрыть stdout и stderr (слегка основываясь на answer этого другого парня ) вот так:

sleep 30 >&- 2>&- &

Вы также можете закрыть стандартный ввод

sleep 30 <&- >&- 2>&- &

или дополнительно откажитесь от вашего дочернего процесса (не для Mac)

sleep 30 <&- >&- 2>&- & disown

На данный момент тестируется только в bash на kubuntu 14.04 и Mac OSX.

11
Joe

Другой способ - отказаться от ребенка.

#!/bin/bash

yourprocess &

disown

Насколько я понимаю, приложение заменяет обычную оболочку bash, потому что оно все еще ожидает завершения процесса, даже если init должен был позаботиться об этом дочернем процессе . Возможно, «application» перехватывает обработку Orphan, которая обычно выполняется init.

В этом случае только параллельный процесс с некоторым IPC может предложить решение (см. Мой другой ответ)

11
thom

Если все остальное терпит неудачу:

  1. Создать именованный канал

  2. запустите «медленный» сценарий независимый из «application», убедитесь, что он выполняет свою задачу в бесконечном цикле, начиная с чтения из канала. Это станет заблокированным для чтения, когда это попытается читать ..

  3. из приложения запустите другой скрипт. Когда нужно вызвать «медленный» скрипт, просто запишите некоторые данные в канал. Медленный скрипт запустится независимо так что ваш скрипт не будет ждать окончания "медленного" скрипта.

Итак, чтобы ответить на вопрос:
bash - как я могу запустить новый процесс, который НЕ является дочерним по отношению к оригинальному процессу?

Просто: не запускайте его, но позвольте независимому объекту запустить его во время загрузки ... как init или на лету с помощью команды at или batch

1
thom

Здесь у меня есть Shell

└─bash(13882)

Где я начинаю такой процесс:

$ (urxvt -e ssh somehost&)

Я получаю дерево процессов (эти выходные данные снимаются с pstree -p):

├─urxvt(14181)───ssh(14182)

где процесс находится под pid 1 (systemd в моем случае).

Однако, если бы я вместо этого сделал это (обратите внимание, где &):

$ (urxvt -e ssh somehost)&

тогда процесс будет дочерним от Shell:

└─bash(13882)───urxvt(14181)───ssh(14182)

В обоих случаях приглашение командной строки немедленно возвращается, и я могу exit, Не прерывая дерево процессов, которое я запустил выше.

В последнем случае дерево процессов переопределяется под pid 1, когда Оболочка завершается, поэтому она заканчивается так же, как в первом примере.

├─urxvt(14181)───ssh(14182)

В любом случае, результатом является дерево процессов, которое переживает Shell. Единственное отличие - это начальные родительские элементы этого дерева процессов.

Для справки, вы также можете использовать

  • Nohup urxvt -e ssh somehost &
  • urxvt -e ssh somehost & disown $!

Оба дают то же дерево процессов, что и во втором примере выше.

└─bash(13882)───urxvt(14181)───ssh(14182)

Когда командная консоль завершается, дерево процессов, как и прежде, перерисовываетсяTo pid 1.

Nohup дополнительно перенаправляет стандартный вывод процесса в файл Nohup.out, поэтому, если это полезная черта, это может быть более полезным выбором.

В противном случае, с первой формой выше, вы сразу получите полностью Отдельное дерево процессов.

0
starfry