Если я начнуасинхронный("фоновый") процесс, некоторая информация, включая PID нового процесса, выводится на терминал перед запуском процесса; например
$ sleep 3 &
[1] 8217
$
[1] + done sleep 3
$
Есть ли способ, чтобы такая информация (особенно PID) была напечатана в начале?каждыйпроцесса, а не только тех, которые запускаются асинхронно?
Фон
Причина этого в том, что из-за особенностей моей повседневной рабочей обстановки, довольно часто случается так, чтосинхронныйДлительно выполняющийся процесс не отвечает Ctrl-C
. (Как правило, «длительно выполняющимися» эти процессы делает то, что они производят гораздо больше выходных данных, чем я ожидал.) Самый надежный способ остановить такой процесс — это запустить kill -9
его из другого окна, и для этого было бы неплохо иметь под рукой его PID.
ОБНОВЛЕНИЕ: В своем первоначальном сообщении я забыл упомянуть, что Ctrl-Z
это не вариант. (Я работаю над оболочкой, работающей под управлением Emacs, поэтому Ctrl-Z
просто приостанавливаю работу Emacs.)
решение1
КакСтивен Китт объясняет, заставить zsh вывести PID будет довольно сложно. Но вы можете получить информацию другими способами.
Вы можете нажать Ctrl+, Zчтобы приостановить процесс, затем zsh отобразит его PID. А если вы хотите завершить его, попробуйте сначала нажать Ctrl+ C, чтобы завершить его напрямую. Если Ctrl+ Cне удается, попробуйте Ctrl+ \для «более жесткого» завершения ( Ctrl+ Cотправляет SIGINT, который обычно говорит программе прекратить текущее действие и вернуть управление пользователю; Ctrl+ \отправляет SIGQUIT, который обычно говорит программе о жестком сбое). Вы можете сделать это даже из Emacs: в режиме Shell нажмите C-c C-z
для перехода C-z
к терминалу, C-c C-c
для передачи C-c
, C-c C-\
для передачи C-\
. В режиме Term C-z
и C-\
передаются напрямую, но вам нужно C-c C-c
передать один C-c
.
Если процесс изменяет настройки терминала или блокирует сигналы, удобный способ найти его для завершения — по терминалу. Узнайте, что это за терминал; вы можете сделать это с помощью команды tty
внутри терминала. Вы можете сделать это частью вашего приглашения или частью заголовка терминала (я поместил это в заголовок терминала). Emacs не отображает заголовок терминала, но он дает вам доступ к информации, оценив следующее выражение:
(process-tty-name (get-buffer-process (current-buffer)))
Чтобы оценить выражение в большинстве режимов, включая режим Shell, введите M-:
и введите выражение. В режиме Term введите C-c M-x eval-expression RET
и введите выражение. Если вы часто этим пользуетесь, привяжите следующую команду к клавише в соответствующих режимах:
(defun buffer-process-tty-name ()
(interactive)
(let ((tty (process-tty-name (get-buffer-process (current-buffer)))))
(if (interactivep) (message "%s" tty))
tty))
Узнав имя терминала, вы можете использовать, например, ps -t pts/42
или pgrep -t pts/42
для вывода списка процессов, подключенных к этому терминалу.
решение2
Похоже, что способа регистрации этой информации не существует, и если рассмотреть ее более подробно, то будет сложно правильно спроектировать (сначала я думал, что это будет сложно реализовать, ноилккачуисправил это).
Я думал, что проблема реализации заключается в регистрации информации в правильном месте. Когда оболочка запускает дочерний процесс, она разветвляется, а затем выполняет дочерний процесс (если только она не может заменить себя дочерним процессом, в этом случае она не разветвляется). Когда разветвляется, процесс дублируется; одна из копий получает код возврата 0 из вызова fork()
, что указывает на то, что это дочерний процесс, а другая получает идентификатор дочернего процесса, что указывает на то, что это родительский процесс. Дочерний процесс наследует файловые дескрипторы родителя, поэтому он может регистрировать свой собственный pid перед настройкой для exec()
.
Проблема дизайна заключается в выборе того, что регистрировать. Если мы регистрируем все процессы, запущенные оболочкой, мы получим множество посторонних журналов,напримердля процессов, участвующих в построении приглашения! Даже для «реальных» команд нам нужно решить, что регистрировать для конвейеров и других составных команд... А затем для согласованности нам нужно придумать что-то для регистрации встроенных команд или для обстоятельств, в которых оболочка заменяет себя дочерней (хотя я не думаю, что это может произойти для интерактивной оболочки, если только вы не вручную exec
).
Если вы хотите изучить этот вопрос более подробно, посмотрите addproc()
и printjobs()
в jobs.c
, и zexecve()
в exec.c
.