it-roy-ru.com

Как мне полностью отсоединить процесс от терминала?

Я использую Tilda (раскрывающийся терминал) в Ubuntu в качестве своего «централизованного командования» - почти так же, как другие могут использовать GNOME Do, Quicksilver или Launchy.

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

  • завершается при закрытии исходящего терминала
  • «загрязняет» исходящий терминал через STDOUT/STDERR

Например, чтобы запустить Vim в «правильном» окне терминала, я попробовал простой скрипт, подобный следующему:

exec gnome-terminal -e "vim [email protected]" &> /dev/null &

Однако, это все еще вызывает загрязнение (также, передача имени файла, кажется, не работает).

297
AnC

Прежде всего; как только вы запустили процесс, вы можете фоновый режим, сначала остановив его (нажмите Ctrl-Z), а затем введите bg, чтобы возобновить работу в фоновом режиме. Теперь это "задание", и его stdout/stderr/stdin по-прежнему подключены к вашему терминалу.

Вы можете сразу начать процесс как фоновый, добавив в его конец символ "&":

firefox &

Чтобы запустить его в фоновом режиме, используйте это:

firefox </dev/null &>/dev/null &

Некоторая дополнительная информация:

Nohup - это программа, которую вы можете использовать для запуска вашего приложения, чтобы вместо нее можно было отправить ее stdout/stderr в файл и чтобы закрытие родительского сценария не SIGHUP дочернего элемента. Тем не менее, вы должны иметь предвидение, чтобы использовать его, прежде чем запустить приложение. Из-за способа работы Nohup вы не можете просто применить его к запущенному процессу .

disown - это встроенная утилита bash, которая удаляет задание Shell из списка заданий Shell. В основном это означает, что вы больше не можете использовать fg, bg, но, что более важно, когда вы закрываете свою оболочку, она больше не будет зависать или отправлять SIGHUP этому дочернему элементу. В отличие от Nohup, disown используется после процесс был запущен и обоснован.

Что вы не можете сделать, так это изменить stdout/stderr/stdin процесса после его запуска. По крайней мере, не из Shell. Если вы запустите свой процесс и скажете ему, что его стандартный вывод - это ваш терминал (то, что вы делаете по умолчанию), то этот процесс настроен для вывода на ваш терминал. Ваша оболочка не имеет никакого отношения к настройке FD процессов, это просто то, чем управляет сам процесс. Сам процесс может решить, закрывать ли его stdout/stderr/stdin или нет, но вы не можете использовать свою оболочку, чтобы заставить его сделать это.

Для управления выводом фонового процесса у вас есть множество опций из сценариев, вероятно, первым приходит на ум "Nohup". Но для интерактивных процессов вы запускаете, но забыли замолчать (firefox < /dev/null &>/dev/null &), на самом деле вы ничего не можете сделать.

Я рекомендую вам получить GNU screen. С помощью экрана вы можете просто закрыть запущенную оболочку, когда вывод процесса становится надоедливым, и открыть новый (^Ac).


Да, и, кстати, не используйте "[email protected]" там, где вы его используете.

[email protected] означает, $1, $2, $3 ..., который превратит вашу команду в:

gnome-terminal -e "vim $1" "$2" "$3" ...

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

Действительно трудно заставить несколько аргументов работать должным образом в заданном вами сценарии (с gnome-terminal -e), потому что -e принимает только один аргумент, который является командной строкой Shell. Вы должны были бы закодировать свои аргументы в один. Лучший и самый надежный, но довольно грубый способ выглядит так:

gnome-terminal -e "vim $(printf "%q " "[email protected]")"
335
lhunath
Nohup cmd &

Nohup полностью отключает процесс (демонизирует его)

197
dsm

Если вы используете bash, попробуйте disown [jobspec]; см. bash (1) .

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

59
Randy Proctor

Прочитав эти ответы, у меня возникло первоначальное впечатление, что выдачи Nohup <command> & будет достаточно. Запустив zsh в gnome-terminal, я обнаружил, что Nohup <command> & не мешает моей командной консоли убивать дочерние процессы при выходе. Хотя Nohup полезен, особенно с неинтерактивными оболочками, он гарантирует такое поведение, только если дочерний процесс не сбрасывает свой обработчик для сигнала SIGHUP.

В моем случае Nohup должен был предотвратить попадание сигналов зависания в приложение, но дочернее приложение (в данном случае VMWare Player) сбрасывало свой обработчик SIGHUP. В результате при выходе из эмулятора терминала он все равно может убить ваши подпроцессы. Насколько мне известно, это можно решить, только убедившись, что процесс удален из таблицы рабочих мест оболочки. Если Nohup переопределяется встроенной оболочкой, как это иногда бывает, этого может быть достаточно, если это не так ...


disown - это встроенная оболочка bash, zsh и ksh93,

<command> &
disown

или же

<command> &; disown

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

После отключения процесс все еще является дочерним для вашего эмулятора терминала (поиграйтесь с pstree, если вы хотите посмотреть это в действии), но после выхода из эмулятора терминала вы должны увидеть, что он подключен к процессу init. Другими словами, все так, как и должно быть, и как вы, вероятно, хотите, чтобы это было.

Что делать, если ваш Shell не поддерживает disown? Я бы настоятельно рекомендовал перейти на тот, который делает, но в отсутствие этого варианта у вас есть несколько вариантов.

  1. screen и tmux могут решить эту проблему, но они гораздо тяжелее, и мне не нравится запускать их для такой простой задачи. Они гораздо больше подходят для ситуаций, в которых вы хотите поддерживать tty, как правило, на удаленной машине.
  2. Для многих пользователей может быть желательно посмотреть, поддерживает ли ваша оболочка такую ​​возможность, как setopt Nohup в zsh. Это можно использовать для указания того, что SIGHUP не следует отправлять заданиям в таблице заданий при выходе из командной консоли. Вы можете применить это непосредственно перед выходом из командной консоли или добавить его в конфигурацию оболочки, например ~/.zshrc, если вы всегда хотите его включить.
  3. Найдите способ отредактировать таблицу вакансий. Я не мог найти способ сделать это в tcsh или csh, что несколько беспокоит.
  4. Напишите небольшую C-программу для разветвления и exec(). Это очень плохое решение, но источник должен состоять только из пары десятков строк. Затем вы можете передавать команды в качестве аргументов командной строки в C-программу и, таким образом, избегать записи, специфичной для процесса, в таблице заданий.
38
Stephen Rosen
  1. Nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Я использовал номер 2 в течение очень долгого времени, но номер 3 работает так же хорошо. Кроме того, disown имеет флаг Nohup-h, может отключить все процессы с помощью -a и может отменить все запущенные процессы с -ar.

Глушение осуществляется с помощью $COMMAND &>/dev/null.

Надеюсь это поможет!

26
Mr. Minty Fresh

в tcsh (и, возможно, в других оболочках) вы можете использовать скобки, чтобы отсоединить процесс.

Сравните это:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

К этому:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

Это удаляет Firefox из списка вакансий, но он все еще привязан к терминалу; если вы вошли в этот узел через 'ssh', попытка выхода из системы все равно приведет к зависанию процесса ssh.

9
Nathan Fellman

Я думаю, что экран может решить вашу проблему

9
dunkyp

Самый простой и единственный правильный ответ для bash:

command & disown

Вам не нужно отсоединять процесс от терминала, но от оболочки.

7
ManuelSchneid3r

Чтобы отключить tty Shell, запустите команду через sub-Shell, например,.

(Команда) &

При выходе использованный терминал закрыт, но процесс все еще жив.

проверять -

(sleep 100) & exit

Откройте другой терминал

ps aux | grep sleep

Процесс еще жив.

7
jitendra

Фоновое и приоритетное задание - это, наверное, одна из первых вещей, которую должен знать каждый системный администратор Unix.

Вот как это делается с помощью bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
6
djangofan

Вы можете запустить свою команду, используя команду Nohup, это отсоединит ваш процесс и перенаправит выходные данные в заданный файл ... но я не уверен, что это именно то, что вам нужно ...

4
Ben

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

2
ShiDoiSi

Просто добавьте это в ваш bashrc/zshrc:

detach() {
  "[email protected]" 1>/dev/null 2>/dev/null &; disown
}

Затем вы можете запустить отрешенные команды, например:

detach gedit ~/.zshrc
2
B. Branchard

В моем .bashrc у меня есть эти функции именно для этой цели:

function run_disowned() {
    "[email protected]" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "[email protected]" 1>/dev/null 2>/dev/null
}

Добавьте команду dos, чтобы запустить ее отдельно от терминала.

Функция написана для работы с bash и zsh.

1
mic_e

Я обнаружил в Mac OS X, что мне нужно использовать как Nohup, так и disown, чтобы гарантировать, что дочерний процесс не будет сорван с терминалом.

0
aaron

Я использую следующий скрипт для этого. Он останавливает процесс печати на терминале, отключается с помощью Nohup и завершает работу со статусом возврата, если команда завершается в пределах TIMEOUT.

#!/bin/bash

TIMEOUT=0.1

CMD=( "[email protected]" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"

#use Nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send Nohup's output to /dev/null, supressing Nohup.out
#run Nohup in the background so this script doesn't block
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
Nohup "${CMD[@]}" >/dev/null 2>&1 &
Nohup_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $Nohup_PID
Nohup_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $Nohup_STATUS != 0 ] && echo "Error: $CMD"
#return the exit status of Nohup, whatever it was
exit $Nohup_STATUS

Пример использования:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
0
jozxyqk