
AT コマンドから実行され、複数回実行される可能性のあるバッチ スクリプトがあります。スクリプトが起動したら、すでに実行されているかどうかを検出し、実行されている場合はすぐに終了する必要があります (2 番目)。
- 堅牢で、スクリプトが予期せず終了した場合にも処理できる必要があります (つまり、開始時にフラグを設定して終了時にクリアすることはできません)
- リモートデスクトップセッションで実行する必要があります
- 私はXPでPowershell v2を使い続けていますが、バッチ/Powershellまたはvbsで実行できない場合は、小さなexeを書いても構いません。
- スクリプトは最小化された状態で実行する必要があるため、Start "NAME" /MIN %COMSPEC% /C "MyScript.bat" で起動します。
- 他のcmdウィンドウが開いている可能性があるので、実行中のスクリプトを確認する必要があります
- バッチスクリプトはSYSTEMユーザーとして実行されますが、WMIは使用できません
PowerShell Get-Process を使用して MainWindowTitle を確認していましたが、コンピューターにリモート接続しているときにスクリプトが実行されている可能性があり、このリモート接続インスタンスには表示されないため、これは機能しませんでした。この場合、cmd プロセスは Get-Process によって表示されますが、MainWindowTitle は空白です。
Get-Process を試し、拡張された StartInfo.EnvironmentVariables プロパティを確認しましたが、プロパティに表示される env var を作成する方法がわかりません。
開始コマンドで /WAIT を使用することを考えましたが、AT は終了するまで開いたままになりますが、AT を含むスクリプトは最小化されません。
何か案は?
答え1
ロック ファイルは最もシンプルで信頼性の高いソリューションであると私は考えています。秘訣は、実行中のバッチ プロセスが終了するまで、ファイルに対する排他的書き込みロックを維持することです。このシステムの優れた点は、バッチがどのような理由で終了しても、Windows がロックを解除することです。
ロックファイルを作成したら、そのファイルが現在ロックされているかどうかを検出する方法が必要です。その方法については、特定のファイルまたはディレクトリがロックされているかどうか (任意のプロセスによって使用されているかどうか) をコマンドラインで確認するにはどうすればよいですか?
私は、この原始的だが効果的な手法を使用して、Windows バッチでかなり高度なタスクを実行しました。
- タスクリストの並列実行、同時プロセスの総数制限
- Windows でログ ファイルを共有するにはどうすればよいですか?
- Powershell または BATCH 経由で symstore の実行をシリアル化する
バッチ ファイルがリモート マシン上かローカル マシン上のどこにあるのか、またはスクリプトを複数のマシン上で同時に実行しているが、マシンごとにアクティブなプロセスが 1 つだけであるかどうかが不明です。
バッチ スクリプトがリモート マシン上にあり、プロセスにスクリプトへの書き込みアクセス権がある場合は、バッチ ファイル自体をロック ファイルとして使用できます。追加モードを使用して、未使用のファイル ハンドルをバッチ スクリプトにリダイレクトしながら、:subroutine を呼び出すだけです。別のプロセスがすでにロックを持っている場合、CALL は失敗します。スクリプトが終了すると (終了方法に関係なく)、ロックは自動的に解除されます。
スクリプト
@echo off
:: Note - this extra call is to avoid a bug with %~f0 when the script
:: is executed with quotes around the script name.
call :getLock
exit /b
:getLock
:: The CALL will fail if another process already has a write lock on the script
call :main 9>>"%~f0"
exit /b
:main
:: Body of your script goes here. Only one process can ever get here
:: at a time. The lock will be released upon return from this routine,
:: or when the script terminates for any reason
exit /b
スクリプトがプロセスとは別のマシン上にあるが、プロセスが一度に 1 台のマシンでのみ実行される場合は、上記の方法は依然として機能すると思います。
おそらく、より良い代替案は、バッチ スクリプトとは別に、各リモート マシンに専用のロック ファイルを作成することです。そうすれば、必要な数のリモート マシンでプロセスを実行できます。
答え2
ご協力ありがとうございます。以下を実装しました。
Before starting my script (in a wrapper script), check whether the lockfile exists:
If it does, read the PID out of it.
If the PID is still a running cmd process, exit my script as another version of it is already running.
If the PID is not still a running cmd process, delete the lockfile
Start the script, and create a new lockfile, containing the PID of the started script
When exiting my script, delete the lockfile
問題なく動作しているようですが、さらにテストすればわかるでしょう。
- 実行中のプロセスを一覧表示するには、POWERSHELL Get-Process を使用します。TASKLIST は WMI を使用しますが、前述したように WMI は利用できません。
- 開始されたスクリプトの PID を特定するには、現在の cmd PID をすべて一覧表示し、スクリプトを開始して、すべての cmd PID を一覧表示し、以前は存在しなかったものを探します。
答え3
ここで使用できる CMDS という自動化プラグインを作成しました:特定のバッチ ファイルが実行中かどうかを確認し、PID を取得するにはどうすればよいですか?ただし、これが XP でも動作するかどうかはわかりません。
コマンド例:CMDS /TS "Your Batch File Title"
単独で使用するための GUI モードも備えています。
ヘルプファイルはこちらです: