我的 Linux 服务器上的 screen 会话中有一个长期运行的服务器进程。它有点不稳定(遗憾的是这不是我的软件,所以我无法修复它!),所以我想编写一个每晚重新启动该进程的脚本来提高稳定性。让它正常关闭的唯一方法是转到 screen 进程,切换到它正在运行的窗口,然后在其控制台上输入字符串“stop”。
我可以进行任何智能重定向扭曲以使 cronjob 每天在固定时间发送停止命令吗?
答案1
这个答案并不能解决问题,但它留在这里,因为有 30 多人认为它有用,不然我早就删掉了。
写入/proc/*pid of the program*/fd/0
。fd
子目录包含所有打开的文件的描述符,文件描述符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 中的一些示例进行了讨论:
--
因此,为了回答近 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