我可以向在 screen 会话中运行的活动进程的 STDIN 发送一些文本吗?

86 linux gnu-screen stdin

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

我可以做任何智能重定向扭曲来让 cronjob 每天在固定时间发送该停止命令吗?

Cri*_*itu 96

这个答案并没有解决问题,但它留在这里是因为 30+ 人认为它很有用,否则我很久以前就会删除它。

写信给/proc/*pid of the program*/fd/0. 在fd子目录中包含的所有打开的文件的描述符和文件描述符0是标准输入(1是stdout和2是标准错误)。

您可以使用它在程序运行的 tty 上输出消息,尽管它不允许您写入程序本身。

例子

1号航站楼:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat
Run Code Online (Sandbox Code Playgroud)

2 号航站楼:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0
Run Code Online (Sandbox Code Playgroud)

  • 真实世界的例子:我已经启动了 gphoto2 --get-all-files 并且它要求确认 100 次。当我回显“y”>/proc/PID/fd/0 时,gphoto2 不会继续,但是,终端中会打印“y”。 (6认同)
  • 请注意,proc fd 仅重定向到用作标准输入源的内容。在您的示例中,如果您在终端 1 中输入某些内容,它将再次打印出来(它被发送到 cat stdin 并 cat 打印它),从而导致您看到它两次。另一方面,如果你向 fd/0 发送一些东西,它将被发送到控制台而不是 cat,因此只显示一次。由于 cat 只是在此示例中再次打印输入,因此您无法真正看到您的输入或输出是否正在打印,因此存在这种误解。/fd/0 指向控制台 /pts;参见`ls -l /proc/7417/fd/0`。 (4认同)
  • @James Lawrie:然后看看 [proc(5)](http://manpages.courier-mta.org/htmlman5/proc.5.html) 和 [proc.txt](http://kernel.org /doc/Documentation/filesystems/proc.txt)。 (3认同)
  • @ThorstenStaerk,我知道,这就是我添加该注释的原因。您只写入与运行 gphoto2 的终端对应的设备文件(例如`/dev/pts/19`),`y` 字符不会到达应用程序本身。这与使用 [**write(1)**](http://man7.org/linux/man-pages/man1/write.1.html) 命令时发生的情况类似。无论如何,要么尝试我的其他答案,要么尝试像 [**xdotool**](http://www.semicomplete.com/projects/xdotool/) 这样的图形自动化工具。 (3认同)
  • +2 无论您认为自己知道多少,总会有更多东西需要学习:) 漂亮。 (2认同)
  • 这并不像 60 人在没有测试的情况下投票的人认为的那样工作。它只是将您重定向的输入打印到您的进程正在运行的虚拟终端,但它不会将您的输入写入该进程的标准输入。 (2认同)

Cri*_*itu 45

基于屏幕的解决方案

像这样启动服务器:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server
Run Code Online (Sandbox Code Playgroud)

screen将以分离模式启动,所以如果你想看看发生了什么,运行:

# screen -r ServerFault
Run Code Online (Sandbox Code Playgroud)

像这样控制服务器:

# 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
Run Code Online (Sandbox Code Playgroud)

(此答案基于将文本输入发送到来自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.
Run Code Online (Sandbox Code Playgroud)

东西[字符串]

   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.
Run Code Online (Sandbox Code Playgroud)

基于 tmux 的解决方案

像这样启动服务器:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server
Run Code Online (Sandbox Code Playgroud)

tmux将以分离模式启动,所以如果你想看看发生了什么,运行:

# tmux attach-session -t ServerFault
Run Code Online (Sandbox Code Playgroud)

像这样控制服务器:

# 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
Run Code Online (Sandbox Code Playgroud)

参数说明

 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.
Run Code Online (Sandbox Code Playgroud)


mar*_*tbn 11

可以在不运行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.


小智 9

有一个更优雅的解决方案,可以避免使用tail -f浪费系统资源的永远循环。

  • 首先创建一个命名管道来通过以下方式路由 STDIN:mkfifo /data/in

  • 然后阻止它进行写入,这样当您的进程读取所有当前内容时它就不会关闭:sleep infinity > /data/in &。永远休眠比这样要好,tailf -f /dev/null因为 tailf 使用 inotify 资源,并且每次某个应用程序向 /dev/null 发送数据时都会触发 tailf。您可以通过运行strace来看到这一点。它也比cat > /dev/null &本身cat与 STDIN 断开连接要好,而 STDIN 又会关闭/data/in

  • /data/in使用提供的 STDIN:在后台启动您的进程application < /data/in &。这比使用尾部管道效果更好tail -f /data/in | application &,因为只有尾部停止时管道才会终止,但如果应用程序崩溃,管道将继续运行。

  • 停止等待应用程序完成。wait $(pidof application)。这不使用任何资源,如果应用程序崩溃,您的代码将在等待后执行。如果您愿意,您可以在其周围添加应用程序重新启动循环。

  • 要优雅地终止应用程序,请使用以下命令将系统信号转发给它:trap 'kill -SIGTERM $(pidof app)' SIGTERM


kri*_*ssi 4

尝试这样开始:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d
Run Code Online (Sandbox Code Playgroud)

还有这个要杀的:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但它可能有一个缺点,即在程序运行时无法发送其他命令。如果程序在 stdin 上遇到 EOF 时停止,那么在第一个 `echo "xxx" &gt; cmd` 时,程序将停止(因为管道将关闭)。尽管有些程序足够聪明,可以在遇到 EOF 时重新打开(“rewind(3)”)其标准输入。 (3认同)