Як повністю відірвати процес від терміналу?


304

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

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

  • припиняється при закритті вихідного терміналу
  • "забруднює" вихідний термінал через STDOUT / STDERR

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

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

Однак це все ще спричиняє забруднення (також, здається, передача імені файлів не працює).


1
Це теж хороше питання. Я думаю, що справедливо вважати Bash мовою програмування - хоча дійсно сфера цього питання, ймовірно, більше стосується системи sysadmin ...

Це дублікат цього питання stackoverflow.com/questions/285015/…
Dana Sane


Ваш випадок використання не описує повного відсторонення, як такого.
jiggunjer

Відповіді:


344

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

Ви можете розпочати процес у фоновому режимі негайно, додавши "&" до кінця:

firefox &

Щоб запустити його у фоновому режимі безшумно, скористайтеся цим:

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

Деякі додаткові відомості:

nohupце програма, яку ви можете використовувати для запуску програми так, щоб її stdout / stderr можна було надіслати у файл замість цього і таким чином, що закриття батьківського скрипту не допоможе дітям. Однак вам потрібно було передбачити, щоб використовувати його перед запуском програми. Через те, як nohupпрацює, ви не можете просто застосувати його до запущеного процесу .

disownце bash вбудований, який видаляє завдання оболонки зі списку завдань оболонки. Це в основному означає, що ви більше не можете його використовувати fg, bgале що ще важливіше, коли ви закриваєте свою оболонку, вона більше не висить і не надсилатиме SIGHUPдитині цю дитину. На відміну від цього nohup, disownвикористовується після запуску процесу та фонового зображення.

Що ви не можете зробити, це змінити stdout / stderr / stdin процесу після його запуску. Принаймні не зі шкаралупи. Якщо ви запустите ваш процес і скажете йому, що його stdout - це ваш термінал (це те, що ви робите за замовчуванням), то цей процес налаштований на вихід на ваш термінал. У вашій оболонці немає жодної справи із налаштуванням FD процесів, це суто те, чим керує сам процес. Сам процес може вирішити, закривати його stdout / stderr / stdin чи ні, але ви не можете використовувати свою оболонку, щоб змусити це робити.

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

Я рекомендую вам отримати GNU screen. За допомогою екрану ви можете просто закрити свою запущену оболонку, коли вихід процесу стає набридним і відкрити нову ( ^Ac).


О, і до речі, не використовуйте " $@" там, де ви його використовуєте.

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

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

Мабуть, це не те, що ви хочете, оскільки -e бере лише один аргумент. Використовуйте, $1щоб показати, що ваш сценарій може обробляти лише один аргумент.

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

gnome-terminal -e "vim $(printf "%q " "$@")"

Дякую за це! На жаль, я можу прийняти лише одну відповідь. Я закінчив "nohup $ @ &> / dev / null &" і "alias wvim = 'start.sh gnome-terminal -x vim" "

20
Яка фантастично детальна та інформативна відповідь. +1
Teekin

1
@ Привіт-Ангел, коли ви закриваєте інтерактивну оболонку bash, програйте HUPs всі активні завдання. Коли ви ^ Z і bg процес, це все-таки робота, будь то фонова. Щоб видалити його як роботу, використовуйте disown, тоді процес буде продовжувати жити, коли ви закриєте оболонку, оскільки баш вже не буде HUP.
lhunath

3
Ви не будете використовувати $*замість того, щоб $@вирішити проблему окремих рядків?
sjas

2
Що ви не можете зробити, це змінити stdout / stderr / stdin процесу після його запуску. - не зовсім так. Використовуйте reptyrдля цього.
Стефан Зайдель

198
nohup cmd &

nohup повністю від'єднує процес (демонізує його)


5
Хоча лаконічна цінність, але повнота цінніша. Хоча nohup - це GNU coreutil, тут буде доречним лише відповідь (лише примітка про те, що не існує). Хоча відповідь хороша.
Обмежене спокута

23
nohupпросто ігнорує SIGHUPсигнал. Він виконує процес нормально. Ніякої демонізації.
nemo

1
@nemo Що означає, що процес не відокремлюється, але стане від'єднаним (і дочірнім init), якби оболонка вийшла ... правда?
Нолдорін

@Noldorin Так. Ігнорування SIGHUP, яке надсилається, коли оболонка припиняється, залишить дочірній процес запущеним та переведеним на init.
nemo

@nemo nohup також замовчує стандартні входи / виходи. Слідкуйте за відхиленням, щоб повністю відійти.
jiggunjer

60

Якщо ви використовуєте bash, спробуйте ; див. bash (1) .disown [jobspec]

Ще один підхід можна спробувати at now. Якщо ви не є суперпользователем, ваш дозвіл на використання atможе бути обмежений.


"disown" не здається внутрішньою командою bash (недоступна на моїй машині, і я використовую bash). "Ногуп", як запропонував Бен, може бути набагато кращим (і стандартним) способом цього зробити.

1
ніколи не думав використовувати "at", дякую за ідею!
кадрій

1
atделегувати виконання комусь іншому, мені це подобається! +1
Ninsuo

1
В якості орієнтиру це також працює zsh.
Кодерер

1
Крім того , disownздається, не має бажаний ефект з gnome-terminal- disownред процеси все ще убитий , коли термінал виходу. Я хотів би знати, чому / як.
Кайл Странд

38

Читаючи ці відповіді, я мав початкове враження, що видачі nohup <command> &буде достатньо. Запускаючи zsh в gnome-терміналі, я виявив, що nohup <command> &не заважало моїй оболонці вбивати дочірні процеси при виході. Хоча nohupце корисно, особливо з неінтерактивними оболонками, воно гарантує таку поведінку лише в тому випадку, якщо дочірній процес не скидає обробник SIGHUPсигналу.

У моєму випадку, nohupслід було б не допустити, щоб сигнали відключення потрапляли до програми, але дочірнє додаток (VMWare Player у цьому випадку) скидає SIGHUPобробник. Як результат, коли емулятор термінала виходить, він все ще може знищити ваші підпроцеси. Наскільки мені відомо, це можна вирішити, лише переконавшись, що процес видалений із таблиці завдань оболонки. Якщо nohupце перекрито вбудованою оболонкою, як це буває, цього, можливо, буде достатньо, якщо це не так ...


disownце оболонка в вбудованої bash, zshі ksh93,

<command> &
disown

або

<command> &; disown

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

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

Що робити, якщо ваша оболонка не підтримує disown? Я б наголосив на переході до того, що є, але за відсутності цього варіанту у вас є кілька варіантів.

  1. screenі tmuxможуть вирішити цю проблему, але вони набагато важчіші за вагою рішення, і мені не подобається виконувати їх для такого простого завдання. Вони набагато більше підходять для ситуацій, коли потрібно підтримувати кількість, як правило, на віддаленій машині.
  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

Вам не потрібно від'єднувати процес від терміналу, але не від оболонки.


7

Для відмежування команди tty shell запускається команда через під-оболонку, наприклад

(команда) &

При виході використаний термінал закритий, але процес залишається активним.

чек -

(sleep 100) & exit

Відкрийте інший термінал

ps aux | grep sleep

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


Це саме те, що мені було потрібно. Я намагався додати ярлик консолі для піднесеного тексту, і він прекрасно працює, ось що я закінчив: ("/ 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

4

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


Я можу покластись, що я спробував nohup перед використанням exec - але, мабуть, не правильно, оскільки він працює так: nohup gnome-terminal -e "vim $ @" &> / dev / null &

2

Спробуйте демон - повинен бути доступний у вашого доброзичливого менеджера пакунків і всебічно піклуватися про всі способи від'єднання від терміналу.


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

Багато відповідей пропонували використовувати ногуп . Я б краще запропонував використовувати pm2 . Використання PM2 над поЬіром має багато переваг, як тримати додаток живим, зберігати лог - файли для програми та багатьох інших інших можливостей. Для більш детальної інформації перевірте це .

Щоб встановити 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
Використання програми NodeJS (порівняно з невеликою та надійною командою на зразок nohup) для управління unix-процесами здається ... справді надмірною, і якщо чесно, досить дивною. Я б використовував monit, якщо вам потрібна функція перезавантаження.
Серхіо

@Sergio - це ваш вибір використовувати оприлюднений додаток.
хакі

Цього року було зроблено кілька релізів (один 4 дні тому), тож я не бачу, як / чому ви можете подумати, що monit є застарілою програмою. @see mmonit.com/monit/changes
Серхіо

Я говорив про ногуп.
hack

1
nohup- це звичайна стандартна команда POSIX, тому те саме зауваження: ні в якому разі вона не застаріла. @see unix.com/man-page/posix/1p/nohup
Серхіо

-1

Якщо ваша мета - просто запустити додаток командного рядка, не зберігаючи вікно терміналу навколо, тоді ви можете спробувати запустити програму після запуску терміналу з alt-F2.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.