シェル スクリプトは別の画面で実行されるコマンドを待機しますか?

シェル スクリプトは別の画面で実行されるコマンドを待機しますか?

私はスケジュールされたシェルスクリプトを書くための最初の一歩を踏み出しました。目標は、Minecraftサーバー用の簡単なバックアップスクリプトを書くことです。サーバーは独自の名前で実行されています。画面

私のスクリプトに次のような内容が含まれていると仮定します

screen -S $(screen_name) -p 0 -X stuff "save-all^M"

サーバー コマンドには時間がかかります。質問ですが、スクリプトはすぐに続行されますか、それともアクセスした画面内のコマンドが完了するまで待機しますか? すぐに戻る場合、どのように待機すればよいですか (この場合、コマンドはsave-all現在の世界を保存します。次のステップはファイルをバックアップ フォルダーにコピーすることなので、世界が正しく保存されるまで待機する必要があります)?

答え1

いいえ。screen -X stuffコマンドはすぐに戻ります。気づかないそもそもコマンドを実行するように要求されているのに、そのコマンドが完了したらさらにそのようになります。実行しているのはキー入力を挿入することだけです (そのため、^M手動で を追加する必要がありました)。偽の tty 入力が送信されるとすぐに、コマンドが返され、スクリプトが続行されます。

一般に、端末エミュレーターとしての screen は、特定の端末ウィンドウで何が起こっているかを正確には認識しません。つまり、シェル プロンプト (またはその他の対話型コンソール プロンプト) を通常の出力から区別するものは何もありません。

(これは根本的に不可能というわけではありません。一部の端末エミュレータでは、シェルが「出力開始/終了」や「プロンプト開始/終了」マーカーを出力できます。例:VSコードまさにそれを実現するために、Bashに特別な設定を注入します。ただし、端末エミュレータのサポートが必要です。そして入力プロンプトを表示するすべてのプログラムからの協力が必要ですが、現時点では Screen も Minecraft もそれを行いません。

一方、スクリプトは単一のプログラムのみを扱うため、待機するだけで済むため、より簡単に実行できる可能性があります。特定のプロンプトを表示させるには、一般的なプロンプトではなく、Screenに現在のバッファの「内容」を問い合わせるループを用意し-X hardcopy、そのバッファの最後の行がないMinecraft のプロンプトがまだ表示されていない場合は、1 秒間スリープして繰り返します。

これはプログラムの動作に似ていますexpect。Expect スクリプトを記述してさまざまな種類の対話型入力を自動化できますが、そのようなスクリプトの中核は常に と のセットですexpect "this"expect "that"つまり、特定のテキストが「プロンプト」であることを事前に認識し、そのテキストを待機します。

[...]
expect "Password:" { send "$password\r" }
expect ">" { send "enable\r" }
expect "Password:" { send "$enablepwd\r" }
expect "#" { send "show run\r" }

他のMinecraft管理スクリプト(例えばこのプロジェクト(最近Screenからtmuxに切り替えた)の問題点としては、1)「save-all」と「stop」の両方を一度に盲目的に送信する、2)サーバーがボットコマンドを処理して自動的に終了するまで待つ、という点が挙げられます。つまり、指示完了するには、結果そのコマンドの。

同様に、保存終了するには、「save-all」コマンドを待つ必要はありません。代わりに、inotifywaitサーバーが特定のファイルの書き込みを完了するまで待つことができます。これを正しく行うのはやや難しい場合があります(通常、inotifywaitを開始するには「coproc」を使用する必要があります)。前にイベントを見逃さないようにコマンドを発行する)が、保存には時間がかかる可能性があるので、おそらく後からやれば大丈夫です。

echo "waiting..."
inotifywait -q -e close_write /path/to/game
echo "probably done!"

一部のプログラムは、他のツールがそれが表示されるまで待機できるように、特定のファイルを意図的に最後に作成します。

echo "waiting..."
until [ -e /path/to/marker_file ]; do sleep 1; done
echo "marker file showed up"

関連情報