我在一台 Ubuntu 10.04 机器上,并通过 ssh 在后台启动了一个服务器 (myserver &)。它运行良好,但我需要一种方法来获取服务器的标准输入,因为控制服务器的唯一方法是通过这种方法。
有没有办法获取已运行进程的标准输入,以便我可以向其写入数据(并希望读取其标准输出)?显然,如果我现在要执行此操作,我会使用 FIFO 重定向到标准输入来启动它,但不幸的是现在有点晚了。
有任何想法吗?
答案1
您可以尝试写入它的 /proc pid 目录。假设您的守护进程的 pid 是 2000,请尝试写入 /proc/2000/fd/0
答案2
您可以使用命名管道(fifo)作为输入来启动服务器:
mkfifo /tmp/srv-input
cat > /tmp/srv-input &
echo $! > /tmp/srv-input-cat-pid
cat /tmp/srv-input | myserver &
避免服务器收到 EOF 非常重要cat > /tmp/srv-input &
。至少一个进程必须以写入方式打开 fifo,这样服务器就不会收到 EOF。此命令的 PID 保存在文件中,/tmp/srv-input-cat-pid
以便稍后终止。
如果您已经启动了服务器,则必须使用调试器(例如,gdb
将其附加到您的进程)将其重定向stdin
到 fifo:
gdb -p PID
call close(0)
call open(0, "/tmp/srv-input", 0600)
然后执行类似下面的操作将输入发送到您的服务器(如果需要,可以在另一个终端窗口中发送):
echo "command" > /tmp/srv-input
要向您的服务器发送 EOF,您需要终止cat > /tmp/srv-input
PID 已保存的进程/tmp/srv-input-cat-pid file
。
对于 GDB 来说,只要退出 GDB 就会发送 EOF。
答案3
与上面相同,但“cat”对我不起作用。文件在发送一个命令后就得到 EOF 并结束。
这对我有用:
#!/bin/bash
mkfifo /tmp/srv-input
tail -f /tmp/srv-input | myserver &
答案4
有一个更优雅的解决方案可以解决 tail -f
和cat
创建一个命名管道来通过以下方式路由 STDIN
mkfifo /data/in
:。阻止它进行写入,因此当您的进程读取所有当前内容时它不会被关闭:
sleep infinity > /data/in &
。
永远休眠比 更好,tailf -f /dev/null
因为 tailf 使用 inotify 资源,并且每次某个应用程序向 /dev/null 发送数据时都会触发。您可以通过运行strace
它来看到这一点。它也比 更好,cat > /dev/null &
因为cat
本身会与 STDIN 断开连接,而 STDIN 又会关闭/data/in
。
/data/in
通过提供 STDIN:在后台启动您的进程application < /data/in &
。
这比使用尾部的管道效果更好,tail -f /data/in | application &
因为只有尾部停止时管道才会终止,但如果应用程序崩溃,管道将继续运行。
- 暂停等待应用程序完成
wait $(pidof application)
。
这不会占用任何资源,如果应用程序崩溃,您的脚本wait
将在执行后执行。如果您愿意,可以为其添加应用程序重启循环。
- 要正常终止应用程序,请捕获系统信号并将其传递给它
trap 'kill -SIGTERM $(pidof app)' SIGTERM