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

304

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

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

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

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

exec gnome-terminal -e "vim $@" &> /dev/null &

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

slhck
источник
1
Это тоже хороший вопрос. Я думаю, что было бы справедливо считать Bash языком программирования - хотя в действительности этот вопрос скорее относится к
Это дубликат этого вопроса stackoverflow.com/questions/285015/…
Дана Нормальная
Ваш вариант использования не описывает полное отделение само по себе.
jiggunjer

Ответы:

344

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

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

firefox &

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

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

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

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

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

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

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

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


Да, и, кстати, не используйте " $@" там, где вы его используете.

$@означает, что $1, $2, $3..., которая превратит вашу команду на:

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

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

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

gnome-terminal -e "vim $(printf "%q " "$@")"
lhunath
источник
Большое спасибо за это! К сожалению, я могу принять только один ответ. Я закончил с «nohup $ @ &> / dev / null &» и «alias wvim = 'launch.sh gnome-terminal -x vim'»
20
Какой фантастически подробный и информативный ответ. +1
Teekin
1
@ Привет-Ангел, когда вы закрываете интерактивную оболочку Bash, Bash HUPs все активные задания. Когда вы ^ Z и управляете процессом, это все еще работа, будь то фоновая. Чтобы удалить его как задание, используйте disown, затем процесс будет продолжать жить после того, как вы закроете оболочку, так как bash больше не будет HUP.
июня
3
Не будете ли использовать $*вместо того, чтобы $@решить проблему отдельных строк уже?
Sjas
2
То, что вы не можете сделать, это изменить stdout / stderr / stdin процесса после его запуска. - не совсем верно. Используйте reptyrдля этого.
Стефан Зайдель
198
nohup cmd &

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

ДСМ
источник
5
Хотя лаконичность ценна, полнота более ценна. Хотя nohup - это GNU coreutil, здесь уместен ответ только для bash (или заметка о том, что его нет). Хороший ответ, тем не менее.
Ограниченное искупление
23
nohupпросто игнорирует SIGHUPсигнал. Он выполняет процесс нормально. Нет демонизации.
Немо
1
@nemo Что означает, что процесс не отделен, но станет отделенным (и потомком init), если оболочка выйдет ... правильно?
Нолдорин
@ Noldorin Да. Игнорирование SIGHUP, которое отправляется после завершения оболочки, оставляет дочерний процесс работающим и перемещается в init.
Немо
@nemo nohup также заглушает стандартные входы / выходы. Продолжайте отрицать, чтобы полностью отделиться.
jiggunjer
60

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

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

Рэнди Проктор
источник
«disown» не является внутренней командой bash (недоступно на моей машине, и я использую bash). «nohup», как предположил Бен, может быть гораздо лучшим (и стандартным) способом сделать это.
1
никогда не думал об использовании "в", спасибо за идею!
Кадриан
1
atделегировать исполнение кому-то еще, мне это нравится! +1
Ninsuo
1
Для справки, это работает и в zsh.
Coderer
1
Кроме того, disownкажется , что не имеет желаемого эффекта gnome-terminal- disownпроцессы все еще убиваются при выходе из терминала. Я хотел бы знать, почему / как.
Кайл Стрэнд,
38

Читая эти ответы, у меня сложилось первоначальное впечатление, что выдачи 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. Другими словами, все так, как и должно быть, и как вы, вероятно, хотите, чтобы это было.

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

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

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

Молчание осуществляется $COMMAND &>/dev/null.

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

Мистер Минти Фреш
источник
Короткая и сладкая; спасибо за это очень полезное резюме!
Шелджон
Я не могу поверить, что я все еще получаю уведомления для этого сообщения ...
Мистер Минти Фреш
9

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


источник
9

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

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

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

К этому:

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

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

Натан Феллман
источник
9

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

command & disown

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

ManuelSchneid3r
источник
7

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

(Команда) &

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

проверить -

(sleep 100) & exit

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

ps aux | grep sleep

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

Jitendra
источник
Это именно то, что мне было нужно. Я пытался добавить консольный ярлык для возвышенного текста, и он отлично работает, вот чем я закончил: ("/ opt / Sublime Text 2 / sublime_text" $ @) &
Ron E
5

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

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

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
djangofan
источник
4

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

Бен
источник
Могу поклясться, что попробовал nohup перед использованием exec - но, видимо, не правильно, поскольку он работает так: nohup gnome-terminal -e "vim $ @" &> / dev / null &
2

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

ShiDoiSi
источник
2

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

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

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

detach gedit ~/.zshrc
Б. Филиал
источник
1

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

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

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

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

мышей
источник
1
Я немного запутался, почему этот ответ использует одну функцию завернутую в другую, когда ее достаточно просто использовать одну функцию с телом , как это: ( "$@" & disown) &> /dev/null. Это также не имеет особого смысла в использовании, 1>и 2>, поскольку вы используете disown, что означает, что вы используете bash, а в bash вы можете легко сделать это &>для перенаправления как stdout, так и stderr
Сергей Колодяжный
У меня есть две функции, потому что (1) я думаю, что так легче читать, и (2) мне нужна run_disownedфункциональность в других местах в моих точечных файлах. Вы правы в этом &>, конечно.
mic_e
0

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

Аарон
источник
0

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

#!/bin/bash

TIMEOUT=0.1

CMD=( "$@" )
#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
>>>
jozxyqk
источник
0

sudo apt install ucommon-utils

pdetach command

Там вы идете :)

d4rk4ng31
источник
-1

Многие ответы предлагали использовать nohup . Я бы скорее предложил использовать pm2 . Использование pm2 по сравнению с nohup имеет много преимуществ, таких как поддержание приложения в рабочем состоянии, поддержка файлов журналов для приложения и множество других функций. Для более подробной информации проверьте это .

Для установки pm2 необходимо скачать npm . Для системы на основе Debian

sudo apt-get install npm

и для Redhat

sudo yum install npm

Или вы можете следовать этим инструкциям . После установки npm используйте его для установки pm2

npm install pm2@latest -g

Как только это будет сделано, вы можете начать свое приложение по

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Для мониторинга процесса используйте следующие команды:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Управляйте процессами, используя имя приложения или идентификатор процесса, или управляйте всеми процессами вместе:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Файлы журналов можно найти в

$HOME/.pm2/logs #contain all applications logs
haccks
источник
1
Использование приложения NodeJS (в отличие от небольшой и надежной команды, такой как nohup) для управления процессами Unix кажется ... действительно излишним, и, честно говоря, довольно странным. Я бы использовал monit, если вам нужна функция перезапуска.
Серхио
@ Sergio это ваш выбор использования приложения с ограниченным доступом.
взломает
В этом году было выпущено несколько релизов (один 4 дня назад), поэтому я не понимаю, как и почему вы можете считать monit устаревшим приложением. @see mmonit.com/monit/changes
Серхио
Я говорил о nohup.
взломает
1
nohupэто простая стандартная команда POSIX, поэтому то же самое замечание: ни в коем случае не рекомендуется. @see unix.com/man-page/posix/1p/nohup
Sergio
-1

Если ваша цель состоит в том, чтобы просто запустить приложение командной строки без сохранения окна терминала, то вы можете попробовать запустить приложение после запуска терминала с помощью alt-F2.

MattKelly
источник