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

Если я начинаю асинхронный («фоновый») процесс, то информация, включая PID нового процесса, печатается на терминале до запуска процесса; например

$ sleep 3 & [1] 8217 $ [1] + done sleep 3 $ 

Есть ли способ получить такую ​​информацию (особенно PID), напечатанную в начале каждого процесса, а не только те, которые начинаются асинхронно?


Задний план

Причина этого в том, что из-за особенностей моей повседневной работы достаточно часто бывает, что синхронный долговременный процесс не отвечает на Ctrl-C . (Неизменно, что заставляет эти процессы «долго работать» – это то, что они производят намного больше результатов, чем я ожидал.) Самый верный способ остановить такой процесс – kill -9 его из другого окна, и было бы хорошо чтобы его ПИД легко под рукой для этого.

UPDATE: В моем первоначальном посте я забыл упомянуть, что Ctrl-Z не вариант. (Я работаю над оболочкой под Emacs, поэтому Ctrl-Z просто приостанавливает Emacs.)

Как объясняет Стивен Китт , делая zsh print, PID будет довольно сложно. Но вы можете получить информацию другими способами.

Вы можете нажать Ctrl + Z, чтобы приостановить процесс, затем zsh отображает его PID. И если вы хотите его убить, сначала нажмите Ctrl + C , чтобы убить его напрямую. Если Ctrl + C завершается с ошибкой, попробуйте Ctrl + \ для «более тяжелого» убийства ( Ctrl + C отправляет SIGINT, который обычно сообщает программе о прекращении текущего действия и обратном управлении пользователем; Ctrl + \ отправляет SIGQUIT, что обычно говорит программа для жесткого сбоя). Вы можете сделать это даже из Emacs: в режиме оболочки нажмите Cc Cz чтобы передать Cz на терминал, Cc Cc чтобы передать Cc , Cc C-\ чтобы передать C-\ . В режиме Term, Cz и C-\ передаются напрямую, но вам нужен Cc Cc для передачи одного Cc .

Если процесс изменяет настройки терминала или блокирует сигналы, удобный способ найти его для убийства – через терминал. Узнайте, что такое терминал; вы можете сделать это с помощью команды tty внутри терминала. Вы можете сделать эту часть своего приглашения или часть названия терминала (я положил его в заголовок терминала). Emacs не отображает заголовок терминала, но дает вам доступ к информации, оценивая следующее выражение:

 (process-tty-name (get-buffer-process (current-buffer))) 

Чтобы оценить выражение в большинстве режимов, включая режим Shell, введите M-: затем введите выражение. В режиме Term введите Cc Mx 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 чтобы просмотреть процессы, подключенные к этому терминалу.

Кажется, что не существует способа регистрации этой информации и более подробно ее рассмотреть, было бы сложно правильно спроектировать (изначально я думал, что это будет сложно реализовать, но ilkkachu исправил это).

Я думал, что проблема реализации связана с регистрацией информации в нужном месте. Когда оболочка запускает дочерний элемент, он вилки, а затем запускает дочерний элемент (если он не может заменить себя дочерним, и в этом случае он не fork). Когда он вилки, процесс дублируется; одна из копий получает код возврата 0 из вызова fork() , который указывает, что он является дочерним, а другой получает идентификатор процесса дочернего процесса, который указывает, что он является родительским. Ребенок наследует дескрипторы файла родителя, поэтому он может регистрировать свой собственный pid, прежде чем настраивать вещи для exec() .

Проблема дизайна – это выбор того, что нужно регистрировать. Если мы запустим все процессы, запущенные оболочкой, мы получим множество посторонних журналов, например, для процессов, связанных с созданием подсказки! Даже для «настоящих» команд нам нужно решить, что регистрировать для конвейеров и других составных команд … И тогда для согласованности нам нужно придумать что-то для входа в встроенные команды или для условий, в которых оболочка заменяет сам с ребенком (хотя я не думаю, что это может произойти для интерактивной оболочки, если только вы вручную не выполняете).

Если вы хотите изучить это дальше, ознакомьтесь с addproc() и printjobs() в jobs.c и zexecve() в exec.c