3

これらは私のために働いていません。

以下の4つの例を明確に修正するための助けはありますか?

CMD.exeを3つ開いていても、EXAMPLE01は「続行」をエコーし​​ます。

----------例01------------

@echo off 
wmic process where name="cmd.exe" | find "cmd.exe" /c
SET ERRORLEVEL=value if "%value%" GTR 1 ( 
    ECHO This batch is not first  
    ECHO quitting ...
    )
if "%value%" LSS 2 ECHO continue

例02で「予期しないiエラー」メッセージが表示されます。

-----------例02-------

@echo off
FOR /F "usebackq tokens=2" %i IN (`tasklist ^| findstr /r /b "cmd.exe"`)
   DO taskkill /pid %%i

例03では、3つのCMD.exeを開いていても、「最初です」というメッセージが表示されます。

-----------例03-------

 @echo off
    wmic process where name="cmd.exe" | find "cmd.exe" /c
    if "%errorlevel%" LEQ 1 echo CMD is first
    if "%errorlevel%" GTR 1 echo CMD is already running

作業中のWmicコマンドにアクセスできない可能性もあるため、例04に別の可能性がありますが、役に立ちません。

-----------例04-------

@echo off
Tasklist /FI "IMAGENAME eq cmd.exe" 2>NUL | find /I /N "cmd.exe">NUL
if "%ERRORLEVEL%"==0 do (goto Use) else (goto Cont)
:Cont
ECHO Only one instance running
pause

:Use
echo Application running already. Close this window

よろしく、マレク

4

2 に答える 2

7

wmzは、OPのコードでいくつかのエラーを識別し、同時実行制御にロックファイルを使用することを提案しています。

以下は、ロックファイルを使用して、バッチファイルの複数のインスタンスが同時に実行されないようにする堅牢なバッチソリューションです。同時実行制御に一時ロックファイルを使用します。ロックファイルが存在するだけでは、スクリプトの実行が停止することはありません。別のプロセスがロックファイルに排他ロックを設定している場合にのみ、スクリプトは失敗します。これは、ロックファイルを削除せずにスクリプトがクラッシュまたは強制終了された場合に重要です。ファイルがロックされなくなったため、スクリプトを実行する次のプロセスは引き続き成功します。

このスクリプトは、スクリプトがローカルドライブにインストールされていることを前提としています。マシン全体で1つのインスタンスのみを許可します。許可される同時実行の量を制御するためのバリエーションはたくさんあります。たとえば、%USERNAME%をロックファイル名に組み込むと、ネットワーク環境でユーザーごとに1つのインスタンスが許可されます。名前に%COMPUTERNAME%を組み込むと、ネットワーク環境のマシンごとに1つのインスタンスが許可されます。

@echo off
setlocal

:: save parameters to variables here as needed
set "param1=%~1"
:: etc.

:: Redirect an unused file handle for an entire code block to a lock file.
:: The batch file will maintain a lock on the file until the code block
:: ends or until the process is killed. The main code is called from
:: within the block. The first process to run this script will succeed.
:: Subsequent attempts will fail as long as the original is still running.
set "started="
9>"%~f0.lock" (
  set "started=1"
  call :start
)
if defined started (
    del "%~f0.lock" >nul 2>nul
) else (
    echo Process aborted: "%~f0" is already running
)
exit /b

:start
:: The main program appears below
:: All this script does is PAUSE so we can see what happens if
:: the script is run multiple times simultaneously.
pause
exit /b


編集

エラーメッセージ「ファイルは別のプロセスによって使用されているため、プロセスはファイルにアクセスできません。」stderr出力を外部ブロックのnulにリダイレクトすることで抑制できます。

2>nul (
  9>"%~f0.lock" (
    set "started=1"
    call :start
  )
)

上記の問題は、メインプログラムのすべてのエラーメッセージも抑制されることです。これは、最初にstderrの現在の定義を別の未使用のファイルハンドルに保存し、次にstderrを保存されたファイルハンドルにリダイレクトするさらに別の内部ブロックを追加することで修正できます。

8>&2 2>nul (
  9>"%~f0.lock" (
    2>&8 (
      set "started=1"
      call :start
    )
  )
)
于 2012-07-24T00:54:45.277 に答える
3
  1. valueどこにも設定しません。変数が解析時に展開されるため、実行したとしても機能しません。設定されたものに対して変数を設定およびテストする必要がある場合は、遅延拡張を使用する必要があります。比較の引用は必要ありません(3を参照)。help set拡張の遅延に関する情報が表示されます。
  2. %iは%%iである必要があります。DO taskkill /pid %%iコマンドの残りの部分と同じ行にある必要がありますforfindstr正規表現モードでも使用します。つまり、 cmd [ anycharacter ]exeを検索します。
  3. 文字列(字句)比較を使用します: "1" leq 1は真です"4" leq 1も...です)。1以上のエラーレベルerrorlevel 1に相当するものを使用します。構文を示しますhelp if
  4. do3プラスインと同じdo (goto Use)ように削除する必要があります。%errorlevel%==0動作しますが、通常はを使用することをお勧めしますerrorlevel number

実行中のcmdが1つだけかどうかを確認する方法:

@echo off
for /f %%i in ('Tasklist /FI "IMAGENAME eq cmd.exe" 2^>NUL' ^| find /I /c  "cmd.exe"') do (
if %%i leq 2 (echo only one instance) else (echo More than one instance)
)

注:これは単なる例です。並行性制御の実際の方法としてこれをお勧めしません。そのためにロックファイルを使用したいと思います。

于 2012-07-23T20:47:02.067 に答える