Ctrl+D соответствует EOT в таблице ASCII. Во многих (большинство?) в случаях это сопоставляется с EOF, что означает, что данных больше нет.
Для терминалов (например, bash
запущенный с tty в качестве stdin
), вызов read()
при отсутствии пользовательского ввода обычно блокирует или возвращает ноль (нет данных для чтения). Когда tty « уходит », bash
, наконец, прочитает EOF, заявив, что входных данных категорически больше нет - никогда. Вы можете представить EOF вручную, набрав Ctrl+D.
Стоит отметить, что такие вещи, как bash
которые используют readline
, не будут представлять EOF, если текущая строка не пуста. Попробуйте набрать что-нибудь, а затем нажмите Ctrl+D - ничего не произойдет.
Когда bash
выполняется со скриптом в качестве входных данных (например, работает с файлом как stdin
), то после прочтения последнего байта read()
вернет EOF. На этом этапе сценарий завершен, и bash
завершает работу. Это то же самое поведение, что и терминал.
Если вы поместите процесс в фоновом режиме (завершите команду с помощью &
или используйте Ctrl+Z и bg
), то вы вернетесь в оболочку. На этом этапе уничтожение оболочки будет иметь разные последствия для процесса, в зависимости от того, что он делает.
- Процесс с файлом
stdin
, скорее всего, продолжит выполняться, теперь он унаследован от init (PID 1).
- Процесс с каналом из
bash
качестве stdin
также продолжит выполняться ... Пока он не попытается вызвать read()
. в этот момент read()
завершится ошибкой, и приложение либо поглотит ошибку и продолжит работу, либо (более вероятно) завершит работу с ошибкой.
SIGHUP
(он же Hang-Up) - это сигнал, который выдается процессу, чтобы сообщить ему, что другой конец «завис». Я ценю, что это может быть загадочной концепцией ... но при таком использовании он сообщает процессу, что SSH-клиент отключился, или сообщает потомку bash
что bash
завершил работу и т. Д ...
Если процесс явно не обрабатывает SIGHUP
, то действием по умолчанию является его завершение. Таким образом, запрос bash
не посылать SIGHUP
одному из его дочерних элементов позволит эффективно запустить его после того, как оболочка исчезнет.
Если вы хотите оставить команду, работающую в фоновом режиме, не закладывая сначала основы (посмотрите на tmux
как на лучшую версию screen
), то вам нужно конкретно указать:« Я больше не хочу, чтобы этот процесс был присоединен к этой оболочке ».
Чтобы достичь этого, вы можете использовать disown
(см. Здесь, но вам нужно будет искать / прокручивать), что поможет вам разобраться и оставит процесс запущенным:
отречься [-ar] [-h] [спецификация работы ...]
Без параметров каждая спецификация заданий удаляется из таблицы активных заданий. Если jobspec отсутствует и не указан ни -a, ни -r, используется оболочка для текущего задания. Если задана опция -h, каждая спецификация заданий не удаляется из таблицы, а помечается так, что SIGHUP не отправляется заданию, если оболочка получает SIGHUP. Если спецификация заданий отсутствует и не указана ни опция -a, ни опция -r, используется текущее задание. Если спецификация заданий не указана, опция -a означает удаление или пометку всех заданий; опция -r без аргумента jobspec ограничивает выполнение операций заданиями. Возвращаемое значение равно 0, если в задании не указано допустимое задание.
Все будет по- прежнему , вероятно , пойдет не так , если процесс пытается read()
из stdin
так что если вы явно хотите отключить запущенный процесс, а затем либо убедитесь , что stdin
указывает на /dev/null
или аналогичный, или использовать tmux
загодя ,
ПРИМЕЧАНИЕ: запись в stdout
или stderr
, вероятно, будет столь же смертельной, как и попытка чтения из stdin
в этих случаях ... SIGPIPE ахой.
Это возможно с помощью инструментов для перенаправления stdin
, stdout
, stderr
запущенного процесса, что делает его более безопасным для выхода с помощью отладочных системных вызовов (у вас могут возникнуть трудности, смотрите это). Я изо всех сил пытаюсь вспомнить название приложения на C, которое я использовал в прошлом, но немного dupx
который также может помочь или, по крайней мере, будет интересным для изучения.
Оба работают в основном следующим образом в рамках целевого процесса:
fd = open("/dev/null", O_RDONLY);
dup2(fd, stdin);
close(fd);
fd = open("/dev/null", O_WRONLY);
dup2(fd, stdout);
dup2(fd, stderr);
close(fd);