SIGTERMを完全に無視するゲームサーバープログラム(SRCDS)を実行しています。サーバーを完全にシャットダウンする唯一の方法は、インタラクティブに「quit」と入力することです。
SIGTERMをキャプチャしてプログラムのSTDINに「終了」を送信するbashスクリプトでこのプログラムをラップする方法はありますか?それ以外の場合、通常の操作では、ラッパーは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
に転送されます。これは子プロセスのpidではなくプロセスのpidです。quit
bc
4771
expect
bc
別のオプションは、ioctlを使用してTIOCSTI
現在の端末に行を挿入することです。quit
ただし、これはシェルでは実行できず、まだ小さな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
このスクリプトがあなたの質問に答えたら、より完全な説明を追加します。