Почему некоторые команды «вешают» терминал, пока они не закончили?

22

Иногда вы запускаете программу из терминала, скажем, lxpanel . Терминал не вернет вас обратно к приглашению, он зависнет. Вы можете нажать Ctrl+, Cчтобы вернуться к подсказке, но это убьет lxpanel. Однако нажатие Alt+ F2(которое открывает окно для принятия команды) и запуск lxpanelработает изящно.

Почему это? Чем отличается запуск команды от терминала и от окна «Выполнить», которое появляется при нажатии Alt+ F2?

lxpanel здесь только что использовался в качестве примера. Я испытал это с несколькими программами

sqram
источник
1
Подсказка: GNU Screen ( screen) может, среди прочего, использоваться для «обертывания» более длительных процессов. Вы можете отсоединиться от него, вернуться к оболочке, затем снова присоединить и увидеть результаты работы запущенного процесса. Присоединение может быть даже сделано из другого терминала, SSH и т. Д. Также могут быть другие программы, которые позволяют вам делать такие вещи.
poplitea

Ответы:

28

По умолчанию терминал будет запускать программу на переднем плане, поэтому вы не попадете обратно в оболочку, пока программа не завершит работу. Это полезно для программ, которые читают из stdin и / или пишут в stdout - вы обычно не хотите, чтобы многие из них запускались одновременно. Если вы хотите, чтобы программа работала в фоновом режиме, вы можете запустить ее так:

$ lxpanel &

Или, если он уже запущен, вы можете приостановить его с помощью Ctrl+, Zа затем запустить, bgчтобы переместить его в фоновый режим. В любом случае вы получите новое приглашение оболочки, но программа все еще работает, и ее вывод появится в терминале (поэтому он может внезапно появиться, пока вы набираете текст)

Некоторые программы (как правило, демоны) при запуске запускают отдельный процесс, а затем сразу же завершают основной процесс. Это позволяет программе продолжать работу без блокировки вашей оболочки

Михаил Мрозек
источник
Так что же на самом деле делает система, когда вы запускаете программу через окно «run» нажатием Alt + f2? (по крайней мере в gnome и openbox, alt + f2 делает это). Я спрашиваю, потому что, как только вы введете команду, программа запустится, и окно исчезнет. это просто добавление & к нему?
sqram
2
@lyrae: по умолчанию оболочка ожидает завершения программы, прежде чем продолжить сеанс оболочки, она не "зависает", по любому определению "зависает"; alt + f2 не ждет программы. Причина, по которой оболочка ожидает завершения программы, заключается в том, что оболочка может перенаправлять все, что пользователь вводит в оболочку, на стандартный ввод программы и / или отображать стандартный вывод программы. Поскольку alt + f2 в основном используется для запуска программы с графическим интерфейсом, alt + f2 не предоставляет возможности использования стандартного ввода / вывода и поэтому не требует ожидания.
Ли Райан
1
@lyrae: alt + f2 не делает ничего особенного, чтобы запустить программу в фоновом режиме; это оболочка, которая делает что-то особенное, добавление '&' - это функциональность оболочки. При запуске команды без '&' оболочка перенаправляет стандартный ввод программы на собственный стандартный ввод, а стандартный вывод программы - на собственный стандартный вывод (немного хитроумно, поскольку оболочка также предоставляет множество других сервисов, таких как перехват Ctrl -C, чтобы послать команду сигнала SIGINT программе переднего плана). '&' Говорит оболочке не делать этого, а просто запустить программу (также надумано).
Ли Райан
1
@LieRyan часть того, что вы говорите, что оболочка делает, фактически обрабатывается драйвером терминала ядра, и «с &» обычно более «особенный», чем «без &», за исключением того, что оболочка вызывает wait () [или waitpid или эквивалентный], который не выполняется alt-f2.
Random832
6

Когда вы запускаете программу в терминале, терминал будет «зависать», пока ваша программа не остановится. Нажав Ctrl+, cвы закрываете свою программу и, таким образом, возвращаетесь к подсказке. Вы увидите это со всеми приложениями с графическим интерфейсом, попробуйте, например, Firefox.

Когда вы используете какой-либо другой метод, такой как Alt + F2 или щелкаете по меню, ваша программа запускается в фоновом режиме, поэтому ничего странного не происходит (и в любом случае нет командной строки).

Если вы все еще хотите запускать приложения с графическим интерфейсом из терминала, добавьте &в конце вашей команды, например, так

lxpanel &

Это говорит терминалу работать lxpanelв фоновом режиме и сразу же дает вам другое приглашение.

phunehehe
источник
3

Программы запускаются через оболочку по умолчанию на переднем плане этой оболочки. Это приводит к тому, что оболочка приостанавливает работу и направляет stdin / stdout / sterr из терминала в программу. Программы, запускаемые через среду рабочего стола, разветвляются , что заставляет их работать независимо от программы, которая их запускала. В большинстве оболочек это можно смоделировать, добавив a &к команде, хотя это все равно будет подключать std * к терминалу (хотя чтение из stdin в фоновой программе имеет дополнительные сложности).

Игнасио Васкес-Абрамс
источник
2

И фоны хорошо, за исключением программ, которые возвращаются позже и требуют взаимодействия с консолью (например, «apt -y update &», которое в конечном итоге переходит в состояние STOP, так как оно хочет предложить пользователю вопрос «действительно действительно принудительно?» Гораздо позже). .... когда никто больше не смотрит).

Чтобы закрыть эту дыру и сообщить процессу, что терминал действительно никогда не станет доступным для него, я добавляю <& - к некоторым из моих команд, полностью отсоединяя их от активного терминала, говоря, что STDIN больше не возможен. Убедитесь, что / bin / bash - это ваша оболочка, если вы ее используете. Скрипт будет регистрировать любые ошибки, связанные с отсутствием псевдотерминала, на который можно было бы разослать любое приглашение.

Например:

`./runme.sh &> runme.log <&- & disown`

мой окончательный способ отделиться от текущей терминальной сессии. И STDOUT, и STDERR регистрируются в runme.log, не имеет значения, завершится ли раньше ваша консоль или оболочка или если вы выйдете / su на другую учетную запись (без мусора терминала из runme), и благодаря тому, что откроет даже родитель-потомок PID отношения удалены.

ОБНОВЛЕНИЕ: даже с этим у меня были проблемы с семафором, связывающим его с именем исходного родителя, поэтому теперь я рекомендую вместо этого:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

Конечно, удалите &>, если вы хотите получать выходные данные из CRON по электронной почте, или перенаправьте все это в / dev / null вместо файла.

Marcos
источник
Чуть менее запутанный способ добиться того, что я начал использовать,at now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Маркос