この質問はこの点に関する議論を開始し、その理由を特定するためにいくつかのテストが行われました。そのため、内部でいくつかのデバッグを行った後cmd.exe
... (これは32 ビット Windows XP cmd.exe 用ですが、動作は新しいシステム バージョンでも一貫しているため、おそらく同じまたは類似のコードが使用されます)
内部ジェブの答えが記載されています
It's a problem with the quotes and %~0.
cmd.exe handles %~0 in a special way
ここでジェブは正しいです。
実行中のバッチ ファイルの現在のコンテキスト内には、現在のバッチ ファイルへの参照があります。これは、実行中のバッチ ファイルのフル パスとファイル名を含む「変数」です。
変数にアクセスすると、その値は使用可能な変数のリストから取得されますが、要求された変数が%0
であり、何らかの修飾子が要求されている (~
が使用されている) 場合は、実行中のバッチ参照 "変数" のデータが使用されます。
しかし、 を使用~
すると、変数に別の効果があります。値が引用符で囲まれている場合、引用符は削除されます。そして、コードにバグがあります。次のようにコーディングされています(ここでは、アセンブラを擬似コードに簡略化しています)
value = varList[varName]
if (value && value[0] == quote ){
value = unquote(value)
} else if (varName == '0') {
value = batchFullName
}
はい、これは、バッチ ファイルが引用されている場合、 の最初の部分if
が実行され、バッチ ファイルへの完全な参照が使用されないことを意味します。代わりに、取得された値は、呼び出し時にバッチ ファイルを参照するために使用される文字列です。
その後どうなりますか?バッチ ファイルがフル パスで呼び出された場合、問題はありません。ただし、呼び出しでフル パスが使用されていない場合は、バッチ呼び出しに存在しないパス内の要素を取得する必要があります。この検索では相対パスを想定しています。
単純なバッチ ファイル ( test.cmd
)
@echo off
echo %~f0
test
(拡張子なし、引用符なし)を使用して呼び出すと、取得しますc:\somewhere\test.cmd
"test"
(拡張子なし、引用符なし)を使用して呼び出すと、取得しますc:\somewhere\test
最初のケースでは、引用符なしで、正しい内部値が使用されます。2 番目のケースでは、呼び出しが引用符で囲まれているため、バッチ ファイルの呼び出しに使用される文字列 ( "test"
) は引用符で囲まれずに使用されます。フル パスを要求しているため、 と呼ばれるものへの相対参照と見なされtest
ます。
これが理由です。の解き方?
C# コードから
バッチファイルから
バッチ ファイルは、任意の場所から任意の方法で呼び出すことができます。現在のバッチ ファイルの情報を取得する唯一の信頼できる方法は、サブルーチンを使用することです。修飾子 ( ~
) が使用されている%0
場合、 は内部の「変数」を使用してデータを取得します。
@echo off
setlocal enableextensions disabledelayedexpansion
call :getCurrentBatch batch
echo %batch%
exit /b
:getCurrentBatch variableName
set "%~1=%~f0"
goto :eof
これは、引用符の有無にかかわらず、ファイルの呼び出し方法に関係なく、現在のバッチ ファイルへのフル パスをコンソールにエコーします。
注: なぜ機能するのですか? %~f0
サブルーチン内の参照が異なる値を返すのはなぜですか? サブルーチン内からアクセスされるデータは同じではありません。がcall
実行されると、新しいバッチ ファイル コンテキストがメモリ内に作成され、内部の「変数」を使用してこのコンテキストが初期化されます。