web-dev-qa-db-ja.com

スクリーンセッションで実行中のアクティブプロセスのSTDINにテキストを送信できますか?

Linuxサーバーのスクリーンセッション内に長時間実行されているサーバープロセスがあります。少し不安定です(残念ながら私のソフトウェアではないので修正できません!)、安定性のために毎晩プロセスを再起動するスクリプトを作成したいと思います。正常なシャットダウンを行う唯一の方法は、画面プロセスに移動し、実行中のウィンドウに切り替えて、コントロールコンソールに文字列「stop」を入力することです。

Cronjobに毎日停止時刻にその停止コマンドを送信させるために実行できるスマートリダイレクトのゆがみはありますか?

74
Richard Gaywood

この答えは問題を解決しませんが、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
88

画面ベースのソリューション

次のようにサーバーを起動します。

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

screen はデタッチモードで起動するので、何が起こっているのかを確認したい場合は、次のコマンドを実行します。

# 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
   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.

スタッフ [文字列]

   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.

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 [-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.
40

開始するにはこれを試してください:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

そしてこれは殺すために:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd
4
krissi

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ジョブは、他の質問に対して人々が書いた例に似たいくつかの小さなユーティリティスクリプト/プログラムを実行する必要があります。質問では、IOCTLタイプのTIOCSTI操作を介して5バイトのそれぞれを送信します。

もちろん、これはTIOCSTIIOCTL操作タイプ(Linuxなど)をサポートするシステムでのみ機能し、rootユーザーアカウントからのみ機能します。これらの「ファイル」は/proc/rootが「所有」しています。

3
maratbn

誰かを助ける場合:
同様の問題があり、使用しているプロセスがscreenまたはtmuxにないため、別のアプローチをとる必要がありました。

プロセスが実行されているgdbxtermをアタッチし、gdbからcall write(5, "stop\n", 5)を使用してマスターptyファイル記述子に書き込みました。
_/proc/<pid>/fd_へのリンクを_/dev/ptmx_で確認し、2つのオプション間で試行錯誤して(一致する両方のファイルに文字列を送信する)、データを送信するファイル記述子を見つけました。記述子は害を引き起こさないようでした)。

私がアタッチしたxtermプロセスは、キーバインディングからのspawn-new-terminal()xtermアクションで生成され、2番目のptmxファイル記述子が開いていることがわかりました閉じられていない親ptmxプロセスのxtermでした。
したがって、試行錯誤の呼び出しにより、その別の端末に出力が送信されました。
ほとんどのxtermプロセスには、2つのptmxファイル記述子がありません。

これにより、その文字列が端末に効果的に入力されたため、その文字列がその下で実行されているプロセスに送信されました。

n.b.あなたは次のようなもので実行中のプロセスにアタッチできるようにする必要があるかもしれません
_Sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"_

1
Apple

(2010年の)Cristian Ciupituの最も受け入れられた回答にはコメントできないので、これを別の回答に入れなければなりません。

この質問はこのスレッドですでに解決されています: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

要するに:

現在の入力が書き込まれたときにブロックもクローズもしないstdinのパイプでプロセスを開始する必要があります。これは、問題のプロセスにパイプされる単純な無限ループによって実装できます。

$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart

これは、私の場合は機能しなかったパイプを開くためのkrissiの方法とは異なることを確認できます。示されたソリューションは代わりに機能しました。

次に、プロセスの.../fd/0ファイルに書き込み、指示を送信できます。唯一の欠点は、サーバーがシャットダウンした後にエンドレスループを実行しているbashプロセスも終了する必要があることです。

1
user3471872