Вопрос или проблема
Иногда я хочу запустить процесс и забыть о нем. Если я запускаю его из командной строки, вот так:
redshift
Я не могу закрыть терминал, иначе это убьет процесс. Могу ли я запустить команду так, чтобы мог закрыть терминал, не убив процесс?
Одна из следующих двух команд должна сработать:
$ nohup redshift &
или
$ redshift &
$ disown
Смотрите следующее для немного большей информации о том, как это работает:
-
Разница между nohup, disown и & (обязательно прочитайте и комментарии)
Если ваша программа уже запущена, вы можете приостановить ее с помощью Ctrl-Z
, перевести в фоновый режим с помощью bg
, а затем disown
, вот так:
$ sleep 1000
^Z
[1]+ Stopped sleep 1000
$ bg
$ disown
$ exit
Хороший ответ уже опубликован @Steven D, но я думаю, что это может немного прояснить ситуацию.
Причина, по которой процесс убивается при завершении терминала, состоит в том, что процесс, который вы запускаете, является дочерним процессом терминала. Как только вы закрываете терминал, это убивает и эти дочерние процессы. Вы можете увидеть дерево процессов с помощью pstree
, например, когда запускаете kate &
в Konsole:
init-+
├─konsole─┬─bash─┬─kate───2*[{kate}]
│ │ └─pstree
│ └─2*[{konsole}]
Чтобы сделать процесс kate
независимым от konsole
при завершении konsole
, используйте nohup
с командой, вот так:
nohup kate &
После закрытия konsole
, pstree
будет выглядеть так:
init-+
|-kate---2*[{kate}]
и kate
выживет. 🙂
Альтернативой является использование screen
/tmux
/byobu
, которые будут держать оболочку работающей, независимо от терминала.
Вы можете запустить процесс так в терминале
setsid process
Это запустит программу в новой сессии, как объясняется в моей статье здесь.
Я предпочитаю:
(applicationName &)
например:
linux@linux-desktop:~$ (chromium-browser &)
Не забудьте использовать скобки при вводе команды!
Хотя все предложенные варианты хорошо работают, я нашел, что мой альтернативный вариант — использовать screen
, программу, которая устанавливает виртуальный терминал на вашем экране.
Вы можете рассмотреть возможность запуска с screen -S session_name
. Screen можно установить практически на всех дистрибутивах Linux и Unix. Нажимая Ctrl+A и (строчная) C, вы начнете вторую сессию. Это позволит вам переключаться между первоначальной сессией, нажимая Ctrl+A и 0, или новой сессией, нажимая Ctrl+A и 1. Вы можете иметь до десяти сессий в одном терминале. Раньше я запускал сессию на работе, возвращался домой, подключался по ssh к своему рабочему компьютеру, а затем вызывал screen -d -R session_name
. Это позволит вам повторно подключиться к этой удаленной сессии.
У меня есть скрипт (я назвал его run
), чтобы:
- Запускать произвольные команды в фоне
- Останавливать их от завершения с закрытием окна терминала
- Подавлять их вывод
- Обрабатывать код завершения
Я использую его в основном для gedit
, evince
, inkscape
и т. д., у которых есть много раздражающего вывода в терминал. Если команда завершается до TIMEOUT
, возвращается код завершения nohup, а не ноль. Содержимое run
:
#!/bin/bash
TIMEOUT=0.1
#используйте nohup для запуска команды, подавляя ее вывод и позволяя закрывать терминал
#также отправьте вывод nohup в /dev/null, подавляя nohup.out
#запускайте nohup в фоне, чтобы этот скрипт не блокировал
nohup "${@}" >/dev/null 2>&1 &
NOHUP_PID=$!
#убийте этот скрипт через короткое время, выходя с успешным статусом - команда все еще работает
#это необходимо, так как у `wait` ниже нет аргумента таймы
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #игнорировать ошибку "Нет такого процесса", если это завершится нормально
#если команда завершается до вышеуказанного времени ожидания, все может быть в порядке или могла произойти ошибка
wait $NOHUP_PID
NOHUP_STATUS=$?
#напечатайте ошибку, если таковая имелась. Чаще всего в команде была опечатка
[ $NOHUP_STATUS != 0 ] && echo "Ошибка ${@}"
#возвращаем код завершения nohup, каким бы он ни был
exit $NOHUP_STATUS
Примеры:
>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Ошибка false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Ошибка notfound
fail
Способ сделать все это только с помощью оболочки — закрыть stdin и отправить команду в фон:
command <&- &
Т тогда она не завершится, когда вы выйдете из оболочки. Перенаправление stdout — приятное дополнительное действие.
Недостаток в том, что вы не можете сделать это задним числом.
Вы можете установить процесс (PID) так, чтобы он не получал сигнал HUP при выходе и завершении сеанса терминала. Используйте следующую команду:
nohup -p PID
Можно утверждать, что это похоже на ответ, предложенный apolinsky, я использую вариант на screen
. Обычная команда выглядит так
screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'
Сессию можно отключить с помощью Ctrl ACtrl D и повторно подключиться к простой сессии с помощью screen -r
. У меня это завёрнуто в скрипт под названием session
, который находится в моем PATH
для удобного доступа:
#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1""https://unix.stackexchange.com/" >/dev/null
then
echo "WARNING: сессия уже запущена (переподключитесь с помощью 'screen -r $1')" >&2
else
exec screen -S "$1" bash -c "$@; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
echo "ERROR: 'screen' не установлен на этой системе" >&2
fi
exit 1
Это работает только тогда, когда вы заранее знаете, что хотите отключить программу. Это не позволяет отключить уже запущенную программу.
Аналогично другим ответам, опубликованным ранее, можно перенести запущенный процесс в screen
с помощью reptyr и затем закрыть терминал. Шаги описаны в этом посте.
Необходимые шаги:
- Приостановите процесс
- Возобновите процесс в фоне с помощью
bg
disown
процесс- Запустите сессию
screen
- Найдите PID процесса
- Используйте
reptyr
для перехвата процесса
Ответ или решение
Запуск процесса в Linux, который продолжит работать после закрытия терминала, представляет собой распространённую задачу для пользователей и разработчиков. Существует несколько методов, позволяющих сделать это, и в этом ответе мы подробно рассмотрим основные из них, а также последствия каждого подхода.
1. Использование nohup
Команда nohup
, сокращение от "no hang up", позволяет запустить процесс, который не будет прекращаться после выхода из терминала. Синтаксис следующий:
nohup redshift &
Здесь &
помещает процесс в фоновый режим, позволяя вам продолжать работу в терминале или закрыть его. nohup
автоматически перенаправляет стандартный вывод и стандартный поток ошибок в файл nohup.out
, если они не перенаправлены явно.
2. Использование disown
Если вы уже запустили процесс и хотите его отсоединить, вы можете использовать команды bg
и disown
. Например:
sleep 1000
^Z
bg
disown
^Z
приостанавливает процесс (т.е. отправляет его в фон);bg
вновь запускает его в фоновом режиме;disown
удаляет его из списка задач текущего сеанса, позволяя закрыть терминал.
3. screen
и tmux
Эти утилиты позволяют создавать виртуальные терминалы, которые продолжают работать даже после закрытия соединения. Для начала работы с screen
, выполните:
screen -S имя_сессии
Внутри сессии вы можете запускать любые команды. Чтобы отделить сессию, нажмите Ctrl+A
, затем D
. Позже вы сможете подключиться к сессии с помощью:
screen -r имя_сессии
В tmux
аналогичные действия, предоставляющие более широкие возможности сессий, можно выполнить так:
tmux new -s имя_сессии
4. setsid
Команда setsid
запускает новую сессию, что позволяет процессу продолжать работу независимо от родительского терминала:
setsid redshift
5. Фоновый запуск с закрытием stdin
Запуск процесса с перенаправлением ввода:
command <&- &
Этот метод закрывает стандартный поток ввода, что предотвращает завершение процесса при закрытии терминала.
6. Использование скрипта run
для управления процессами
Можно создать скрипт, который будет управлять фоновыми задачами с использованием nohup
и скрытого вывода. Пример скрипта:
#!/bin/bash
nohup "$@" >/dev/null 2>&1 &
Этот скрипт принимает команду как аргумент и выполняет ее в фоновом режиме, скрывая вывод.
7. Использование reptyr
для переноса процессов
Если процесс уже запущен, но вы хотите отделить его от терминала, можно использовать reptyr
. Этот инструмент позволяет перехватить запущенный процесс и присоединить его к сессии screen
или tmux
. Инструкции:
- Приостановите текущий процесс (
Ctrl+Z
). - Запустите его в фоновом режиме (
bg
). - Используйте
disown
.
После этого войдите в новую сессию screen
и используйте reptyr PID
, где PID
— идентификатор процесса, который вы хотите перенести.
Заключительные рекомендации
Выбор метода зависит от ваших потребностей и сценария использования. nohup
подходит для простых задач, в то время как screen
и tmux
предлагают более гибкие возможности управления сессиями. Будьте внимательны при использовании этих команд, чтобы избежать неожиданных остановок процессов.
Правильное применение этих техник поможет вам эффективно управлять задачами в Linux и обеспечит бесперебойную работу важных процессов.