Я використовую `&`: чому процес не працює у фоновому режимі?


24

Я знаю, що можу додати &команду для запуску процесу у фоновому режимі.

Я SSH'ing в коробку Ubuntu 12.04 і запускаю програму python з $python program.py &- але коли я йду закривати вікно терміналу, я отримую повідомлення про те, що закриття терміналу вбиває запущений процес.

Чому це? Я використовую ampersand для запуску процесу у фоновому режимі. Як я можу змусити його запускатись незалежно від того, якщо я в SSH'ed?



apt-get install screen, man screen
captcha

Відповіді:


51

Коли ви закриєте вікно терміналу, емулятор термінала надсилає SIGHUP до процесу, який він працює, вашої оболонки. Потім ваша оболонка пересилає цей SIGHUP до всього, що він працює. У вашій локальній системі це ssh. Потім ssh пересилає SIGHUP на те, що він працює, на віддалену оболонку. Тоді ваша віддалена оболонка відправляє SIGHUP на всі його процеси, на вашу фонову програму.

Є два шляхи навколо цього.

  1. Від'єднайте фонову програму від вашої оболонки.
    1. Використовуйте disownкоманду після фонового процесу. Це змусить оболонку забути про неї.
    2. Префікс вашої команди за допомогою nohup( nohup $python program.py &). Це здійснює те саме, але за допомогою проміжного процесу. В основному він ігнорує сигнал SIGHUP, а потім розгортає та виконує вашу програму, яка успадковує налаштування, а потім виходить. Оскільки він роздвоєний, запущена програма не є дочірньою оболонкою, і оболонка не знає про неї. І якщо він не встановить обробник сигналу для SIGHUP, він все одно зберігає дії ігнорування.
  2. Використовуйте logoutзамість того, щоб закривати вікно терміналу. Коли ви використовуєте logout, це не SIGHUP, і тому оболонка не надсилатиме SIGHUP жодному зі своїх дітей.

Крім того, ви повинні переконатися, що ваша програма не записує в термінал через STDOUT або STDERR, оскільки обидва вони більше не існуватимуть, коли термінал вийде. Якщо ви не переспрямовуєте їх на щось подібне /dev/null, програма все одно запуститься, але якщо вона спробує записати на них, вона отримає SIGPIPE, а дія SIGPIPE за замовчуванням - це вбити процес).


4
Технічно sshвмирання призводить до того, що з'єднання впадає, а з'єднання, яке випадає, призводить sshdдо того, що інший кінець гине. Цей sshd, що керує головним боком псевдотерміналу, яким запускається віддалений оболонок, коли він гине, це зависання (це як витягування штекера на справжньому терміналі), тому система надсилає SIGHUP до віддаленої оболонки.
Стефан Шазелас

@ StéphaneChazelas Це одне, чого я ніколи не копав. Якщо це ядро ​​робить це, як воно визначає, який процес SIGHUP? Очевидно, НЕ ЗНАЧІТЬ усе, що має відкритий дескриптор файлу до цього TTY, оскільки програми залишатимуться до тих пір, поки вони не намагаються його використовувати. Тож чи вибирає він програму, яку зараз читають зі STDIN (оскільки одночасно може читати лише STDIN)?
Патрік

4
Неважливо, відповів на моє власне питання. Розділ 11 POSIX IEEE 1003.1, Якщо інтерфейс термінала для керуючого терміналу виявив відключення модему ... сигнал SIGHUP надсилається до керуючого процесу .
Патрік

2
Також зауважте, що nohupстворюється nohup.outфайл із результатом програми, яку ви починаєте з нього. Може бути прикро видаляти цей файл щоразу, коли ви використовували nohup таким чином, щоб запустити додаток таким чином (або вам потрібно буде перенаправити його вихід на /dev/null).
Руслан

1
Замість цього nohup python program.py &я б рекомендував використовувати setsid python program.pyнатомість, що негайно відмовляється від програми.
Hitechcomputergeek

14

Процес працює у фоновому режимі в терміналі, але вихід з stdoutstderr) все ще надсилається до терміналу. Щоб зупинити це, додайте > /dev/null 2>&1перед тим, &щоб перенаправити обидва виходи на /dev/null- додавання disownтакож гарантує, що процес не загине після закриття терміналу:

COMMAND > /dev/null 2>&1 & disown

У вашому випадку це було б:

python program.py > /dev/null 2>&1 & disown

3

Ці &команди оператора Розділяє працювати паралельно, так само , як ;Розділяє команди для запуску послідовно. Обидва типи команд все ще будуть виконуватись як дочірній процес оболонки .

Отже, коли ви закриєте оболонку, яку запустили ці діти, діти також будуть закриті.

Те, що, здається, хоче - це демон-процес , який є значно складнішим, оскільки йому потрібно повністю відмежуватися від батьківського процесу. Оболонка зазвичай не має простого способу зробити це.


1

Коли ви виходите з системи, фонові процеси, пов’язані з сеансом входу, також зазвичай знищуються. Якщо ви хочете, щоб вони були відключені від сеансу, запустіть їх nohup.

nohup python program.py &

1

Після закінчення команди ampersand ( &) у командному рядку запустіть команду bg:

bash> python program.py &  
bash> bg  

Це поставить команду "&" на задній план

bash> jobs  

Тут буде перераховано завдання, які виконуються у фоновому режимі

bash> fg 1   

Це виведе Іова №1 на перший план

Інший спосіб (щоб мати можливість вийти з системи)

bash> at now  
bash> /full/path/python /full/path/program.py  
bash> ^d   `(# That is, Control-D, to run the command, Control-C to cancel)`  

Кілька рядків можна подати до atкоманди, перш ніж ^ d (Control-D)
див man at.

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