使用 Bash 包装交互式进程以注入 STDIN

使用 Bash 包装交互式进程以注入 STDIN

我正在运行一个完全忽略 SIGTERM 的游戏服务器程序(SRCDS)。彻底关闭服务器的唯一方法是交互式地键入“quit”。

有什么方法可以将此程序包装在 bash 脚本中,该脚本将捕获 SIGTERM 并将“退出”发送到程序的 STDIN?否则,在正常操作中,包装器应该转发 STDIN 和 STDOUT,就好像根本不存在一样。

我想要实现的目标的图表:

普通手术:

--- STDIN --->  |             |  --- STDIN --->  |                |
                | Bash Script |                  | Server Program |
<-- STDOUT ---  |             |  <-- STDOUT ---  |                |

SIGTERM 发送:

                                     "quit"
--- STDIN --->  |             |  --- STDIN --->  |                |
-- SIGTERM -->  | Bash Script |                  | Server Program |
<-- STDOUT ---  |             |  <-- STDOUT ---  |                |

答案1

这取决于该程序是否期望从终端运行。如果是的话,我认为你不能这样做bash;你应该使用类似的东西expect。例子:

包装器.期望:

puts "<<< pid=[pid] >>>"
spawn {*}$argv
trap {send "quit\n"} SIGTERM
interact

以 bc 为例:

expect wrapper.expect bc -q

<<< pid=4771 >>>
spawn bc -q

kill 4771来自另一个窗口的A将导致expect向 发送quit一行bc。请注意,这4771是进程的 pid expect,而不是bc子进程的 pid。

另一种选择是使用ioctl在当前终端中TIOCSTI注入该行;quit但同样,您将无法从 shell 中执行此操作;你仍然需要一些小的 C(或 perl、python 等)程序来调用ioctl()(并且TIOCSTI已经在 OpenBSD 等系统中被删除)。

答案2

尝试这个:

#!/bin/bash

coproc cat -n  # replace 'cat -n' with actual server program to be launched

# first some necessary file-descriptors fiddling
exec {srv_input}>&${COPROC[1]}-
exec {srv_output}<&${COPROC[0]}-

# background commands to relay normal stdin/stdout activity
cat <&0 >&${srv_input} &
cat <&${srv_output} >&1 &

# set signal handler up
term_received=false ; trap 'term_received=true' SIGTERM

# endless loop waiting for events
while true; do
    # wait for server to exit or sigterm received
    wait ${COPROC_PID}
    exit_status=$?
    # if sigterm received:
    if [ $exit_status -gt 128 ] && $term_received ; then
        # kill proxy command relaying stdin to server
        kill %2
        # send quit to server's stdin
        echo $'\n'quit >&${srv_input}
        # close server's stdin
        exec {srv_input}<&-
        # wait for actual server to exit
        wait ${COPROC_PID}
        exit $?
    # something else happened: kill proxy commands and exit with server's own exit status
    else
        kill %2
        kill %3
    fi
    exit $exit_status
done

如果这个脚本回答了您的问题,我将添加更完整的解释

相关内容