Назад | Перейти на главную страницу

Могу ли я отправить текст на STDIN активного процесса, запущенного в сеансе экрана?

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

Могу ли я сделать какие-то умные переадресации, чтобы cronjob отправлял эту команду остановки в определенное время каждый день?

Этот ответ не решает проблему, но он оставлен здесь, потому что 30+ человек сочли его полезным., а то давно бы удалил.

Написать в /proc/*pid of the program*/fd/0. В fd подкаталог содержит дескрипторы всех открытых файлов и файловый дескриптор 0 - стандартный ввод (1 - стандартный вывод, а 2 - стандартный ввод).

Вы можете использовать это для вывода сообщений на tty, на котором работает программа, хотя это не позволяет вам писать в саму программу.

пример

Терминал 1:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat

Терминал 2:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0

Решение на основе экрана

Запускаем сервер так:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

экран запустится в автономном режиме, поэтому, если вы хотите увидеть, что происходит, запустите:

# screen -r ServerFault

Управляйте сервером так:

# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF

(этот ответ основан на отправка ввода текста на отдельный экран из Unix и Linux братский сайт)

Объяснение параметров:

-d -m
   Start screen in "detached" mode. This creates a new session but doesn't
   attach to it.  This is useful for system startup scripts.
-S sessionname
   When creating a new session, this option can be used to specify a meaningful
   name for the session.
-r [pid.tty.host]
-r sessionowner/[pid.tty.host]
   resumes a detached screen session.
-p number_or_name|-|=|+
   Preselect a window. This is useful when you want to reattach to a specific
   window or you want to send a command via the "-X" option to a specific
   window.
-X
   Send the specified command to a running screen session e.g. stuff.

вещи [строка]

   Stuff the string string in the input  buffer of the current window.
   This is like the "paste" command but with much less overhead.  Without
   a parameter, screen will prompt for a string to stuff.

решение на основе tmux

Запускаем сервер так:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server

tmux запустится в автономном режиме, поэтому, если вы хотите увидеть, что происходит, запустите:

# tmux attach-session -t ServerFault

Управляйте сервером так:

# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF

Объяснение параметров:

 new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s
         session-name] [-t target-session] [-x width] [-y height]
         [shell-command]
         Create a new session with name session-name.

         The new session is attached to the current terminal unless -d is
         given.  window-name and shell-command are the name of and shell
         command to execute in the initial window.  If -d is used, -x and
         -y specify the size of the initial window (80 by 24 if not
         given).

 send-keys [-lR] [-t target-pane] key ...
               (alias: send)
         Send a key or keys to a window.  Each argument key is the name of
         the key (such as `C-a' or `npage' ) to send; if the string is not
         recognised as a key, it is sent as a series of characters.  The
         -l flag disables key name lookup and sends the keys literally.

Можно отправить вводимый текст в работающий процесс без запуска screen утилита или любая другая необычная утилита. И это можно сделать, отправив этот входной текст в стандартный входной "файл" процесса. /proc/PID#/fd/0.

Однако вводимый текст должен быть отправлен особым образом, чтобы процесс мог его прочитать. Отправка вводимого текста через обычный файл write не приведет к тому, что процесс получит текст. Это потому, что это только добавит к этому «файлу», но не запустит процесс для чтения байтов.

Чтобы запустить процесс чтения байтов, необходимо выполнить IOCTL операция типа TIOCSTI для каждого отправляемого байта. Это поместит байт в стандартную входную очередь процесса.

Это обсуждается здесь с некоторыми примерами на C, Perl и Python:

https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty/48221

-

Итак, чтобы ответить на исходный вопрос, заданный почти 9 лет назад, задание cron должно было бы запустить небольшой служебный скрипт / программу, аналогичную примерам, которые люди написали для этого другого вопроса, которая отправит строку «stop \ n» этому серверному процессу. в вопросе, отправив каждый из 5 байтов через IOCTL операция типа TIOCSTI.

Конечно, это будет работать только в системах, поддерживающих TIOCSTI IOCTL тип операции (как в Linux), и только от root учетной записи пользователя, поскольку эти "файлы" под /proc/ "принадлежат" root.

Попробуйте это для начала:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

И это убить:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd

Если это кому-то поможет:
У меня была аналогичная проблема, и поскольку процесс, который я использовал, не находился под screen или tmux, Мне пришлось использовать другой подход.

Я прикрепил gdb к xterm что мой процесс работал, и использовал call write(5, "stop\n", 5) из gdb для записи в дескриптор главного файла pty.
Я выяснил, в какой файловый дескриптор отправлять данные, посмотрев на /proc/<pid>/fd для ссылки на /dev/ptmx а затем методом проб и ошибок между двумя вариантами (отправка моей строки в оба совпадающих файловых дескриптора, похоже, не причинила вреда).

EDIT

Оказалось, что xterm процесс, к которому я подключился, был порожден spawn-new-terminal() xterm действие от привязки клавиш, а второй ptmx дескриптор файла был просто ptmx родителя xterm процесс, который не был закрыт.
Следовательно, вызовы проб и ошибок отправили вывод на этот другой терминал.
Наиболее xterm у процессов нет двух ptmx файловые дескрипторы.

END EDIT

Это эффективно ввело эту строку в терминал и, следовательно, отправило ее процессу, работающему под ним.

n.b. вам может потребоваться разрешить подключение к запущенному процессу с помощью чего-то вроде
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"

Поскольку я не могу прокомментировать наиболее распространенный ответ Кристиана Чупиту (2010 г.), я должен выделить его в отдельный ответ:

Этот вопрос уже решался в этой ветке: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

Коротко:

Вы должны начать свой процесс с канала для stdin, который не блокируется и не закрывается, когда текущий ввод был записан. Это может быть реализовано с помощью простого бесконечного цикла, который будет передан рассматриваемому процессу:

$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart

Я могу подтвердить, что это отличается от способа Крисси открыть трубу, который не работал в моем случае. Показанное решение действительно работало.

Затем вы можете записать в файл ... / fd / 0 процесса, чтобы отправить ему инструкции. Единственный недостаток заключается в том, что вам также необходимо завершить процесс bash, который выполняет бесконечный цикл после того, как сервер завершил работу.