Как сделать так, чтобы PID выводился на терминал в начале *каждого* процесса?

Как сделать так, чтобы PID выводился на терминал в начале *каждого* процесса?

Если я начнуасинхронный("фоновый") процесс, некоторая информация, включая 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.

Связанный контент