我可以将一些文本发送到屏幕会话中运行的活动进程的 STDIN 吗?

我可以将一些文本发送到屏幕会话中运行的活动进程的 STDIN 吗?

我的 Linux 服务器上的 screen 会话中有一个长期运行的服务器进程。它有点不稳定(遗憾的是这不是我的软件,所以我无法修复它!),所以我想编写一个每晚重新启动该进程的脚本来提高稳定性。让它正常关闭的唯一方法是转到 screen 进程,切换到它正在运行的窗口,然后在其控制台上输入字符串“stop”。

我可以进行任何智能重定向扭曲以使 cronjob 每天在固定时间发送停止命令吗?

答案1

这个答案并不能解决问题,但它留在这里,因为有 30 多人认为它有用,不然我早就删掉了。

写入/proc/*pid of the program*/fd/0fd子目录包含所有打开的文件的描述符,文件描述符0是标准输入(1 是 stdout,2 是 stderr)。

您可以使用它在程序正在运行的 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

答案2

基于屏幕的解决方案

像这样启动服务器:

# 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
  开始屏幕分离的模式。这将创建一个新会话,但不会附加到它。这对于系统启动脚本很有用。

-S 会话名称
  将新会话的名称设置为会话名称

-r[pid.tty.主机]
-r 会话所有者/[pid.tty.主机]
  恢复分离的屏幕会话。

-p 号码或姓名|-|=|+
  预先选择一个窗口。当您想要重新附加到特定窗口或想要通过选项-X向特定窗口发送命令时,这很有用。

-X
  将指定的命令发送到正在运行的屏幕会话,例如 stuff。

stuff[细绳]
  塞入字符串细绳在当前窗口的输入缓冲区中。这就像paste命令,但开销要小得多。如果没有参数,screen 将提示输入要填充的字符串。您无法使用该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[—AdDEPX][-C 起始目录][-e 环境][-F 旗帜][-F 格式][-n 窗口名称][-s 会话名称][-t 团队名字][-X 宽度][-y 高度][shell 命令]
(别名: new)
  创建一个名为的新会话会话名称.
  新会话将附加到当前终端,除非-d给出。窗口名称shell 命令是在初始窗口中执行的 shell 命令的名称。

send-keys[—FHlMRX][-N重复计数] [-t 目标窗格]钥匙
(别名send:)
  向窗口发送一个或多个键。每个参数钥匙是要发送的密钥的名称(例如“Ca”或“NPage”);如果字符串未被识别为密钥,则将其作为一系列字符发送。所有参数均按从第一个到最后一个的顺序发送
  。-l标志禁用键名称查找并将键作为文字 UTF-8 字符处理。-H标志期望每个键都是 ASCII 字符的十六进制数。

答案3

无需运行该实用程序或任何其他花哨的实用程序,即可将输入文本发送到正在运行的进程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”发送到问题中的服务器进程,通过IOCTL类型操作发送 5 个字节中的每一个TIOCSTI

当然,这只在支持TIOCSTI IOCTL操作类型的系统(如 Linux)上有效,并且只能从root用户帐户运行,因为这些下的“文件”/proc/归“所有” root

答案4

尝试这样做:

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

这会杀死:

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

相关内容