287

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

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

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

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

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

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

18 ответов18

322

Прежде всего; как только вы начали процесс, вы можете запустить его в фоновом режиме, сначала остановив (нажав 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 &), на самом деле вы ничего не можете сделать.

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


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

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

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

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

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

gnome-terminal -e "vim $(printf "%q " "$@")"
196
nohup cmd &

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

57

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

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

37

Прочитав эти ответы, у меня возникло первоначальное впечатление, что выдачи 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 и, таким образом, избегать записи, специфичной для процесса, в таблице заданий.
26
  1. nohup $ COMMAND &

  2. $ COMMAND & disown

  3. команда setsid

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

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

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

9

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

8

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

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

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

К этому:

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

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

7

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

command & disown

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

7

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

(Команда)&

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

проверять -

(sleep 100) & exit

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

ps aux | grep sleep

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

5

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

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

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

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

2

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

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 .

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
>>>
-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
-1

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .