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


69

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

毎日決まった時間にcronジョブにその停止コマンドを送信させるためにできるスマートなリダイレクトの歪みはありますか?

回答:


85

この答えは問題を解決しませんが、30人以上の人がそれを便利だと思ったので、それはここに残っています

への書き込み/proc/*pid of the program*/fd/0fdサブディレクトリには、すべての開いているファイルの記述子が含まれており、ファイルディスクリプタは、0標準入力(1はstdoutですと2は標準エラー出力である)です。

これを使用して、プログラムが実行されている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


2
+2あなたがどれだけ知っていると思っていても、学ぶべきことは常にあります:)なめらか。
トロイエンゲル

3
ただし、proc fdはstdinのソースとして使用されるものにのみリダイレクトすることに注意してください。この例では、ターミナル1に何かを入力すると、それが再び出力され(cats stdinに送信され、catが出力します)、2回表示されます。一方、fd / 0に何かを送信すると、コンソールには送信されますが、catには送信されないため、1回だけ表示されます。catはこの例で入力を再度出力するだけなので、入力または出力が印刷されているかどうかは実際にはわかりません。したがって、この誤解です。/ fd / 0はコンソール/ ptsを指します。をご覧くださいls -l /proc/7417/fd/0
キサキ

4
実際の例:gphoto2 --get-all-filesを開始しましたが、確認を100回要求されます。「y」> / proc / PID / fd / 0をエコーすると、gphoto2は処理されませんが、端末に「y」が出力されます。
トールステンスターク

2
@ThorstenStaerk、私は知っている、それは私がそのメモを追加した理由です。gphoto2が実行されている端末に対応するデバイスファイル(例:)にのみ書き込みをしている/dev/pts/19場合、yキャラクターはアプリケーション自体に到達しません。これは、write(1)コマンドを使用した場合と同様です。とにかく、他の答えを試すか、xdotoolのようなグラフィカルな自動化ツールを試してください
クリスチャン・シウピトゥ

36

スクリーンベースのソリューション

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

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

画面は切り離されたモードで起動するので、何が起こっているのかを確認したい場合は、次を実行します:

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

4

これを試してみてください:

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

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

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

3
これは良いことですが、プログラムの実行中に他のコマンドを送信できないという欠点がある場合があります。stdinでEOFに達したときにプログラムが停止すると、最初echo "xxx" > cmdにプログラムが停止します(パイプが閉じられるため)。一部のプログラムはrewind(3)、EOFに遭遇したときにstdin を再開()できるほどスマートです。
クリスチャンシウピトゥ

2

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は、タイプの操作を介して5バイトのそれぞれを送信しますTIOCSTI

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


1

それが誰かを助ける場合:
私は同様の問題を抱えていた、そして私が使用していたプロセスが下screenまたは下ではなかったのでtmux、私は別のアプローチをとらなければならなかった。

プロセスを実行しgdbているxtermものにアタッチし、call write(5, "stop\n", 5)from gdbを使用してマスターptyファイル記述子に書き込みました。リンクを
探して2つのオプション間の試行錯誤を行っ/proc/<pid>/fdて、データを送信するファイル記述子を見つけました/dev/ptmx(一致する両方のファイル記述子に文字列を送信しても問題はないようです)。

編集

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

編集を終了

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

nbあなたは次のようなもので実行中のプロセスに接続できるようにする必要があるかもしれません
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"


0

(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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.