次を使用するだけで、最初のバッチ スクリプトで同じ結果を得ることができます。
call test.bat "blabla,blabla,^>blabla", "blaby"
あなたの問題は、バッチ処理が CALL ステートメントを解析する方法の残念な側面から生じています。Windows コマンド インタープリター (CMD.EXE) はスクリプトをどのように解析しますか? のフェーズ 6 で説明されています。.
痛い-以前はキャレットの倍増を理解していたと思いましたが、明らかに違いました。jeb のコメントに応えて、以下の議論を大幅に編集しました。
CMD.EXE の設計者は、ステートメント likecall echo ^^
が と同じ結果を出すことを望んでいecho ^^
ます。どちらのステートメントも、特殊文字が処理されるフェーズ 2 に縮小^^
されます。^
ただし、CALL ステートメントはフェーズ 1 とフェーズ 2 をもう一度実行する必要があります。そのため、舞台裏では、CMD.EXE がフェーズ 6 で CALL ステートメントを認識すると、残りのキャレットを に倍増し、^^
フェーズ 2 の 2 回目のラウンドで に戻し^
ます。どちらのステートメントも、単一のキャレットを画面にエコーします。
残念ながら、CMD.EXE は、引用符で囲まれていても、盲目的にすべてのキャレットを二重化します。ただし、引用符で囲まれたキャレットはエスケープとして扱われず、リテラルです。キャレットは消費されなくなりました。非常に残念です。
実行中はパーサーのフェーズ 6 になりますcall test.bat "blabla,blabla,^>blabla", "blaby"
。call test.bat "blabla,blabla,^^>blabla" "blaby"
これは、ARG 1 が出力でのように見える理由を簡単に説明しています。
どこに行ったblabla
のかというと、それは少しトリッキーです。
スクリプトが を実行するSET list=%~1
と、引用符が削除され、^^
はエスケープされたキャレットとして扱われ、 に縮小され、エスケープされ^
なく>
なります。したがって、SET ステートメントの出力は「blabla」ファイルにリダイレクトされます。もちろん、SET には出力がないため、ハード ドライブには長さゼロの「blabla」ファイルが必要です。
編集 - 「後期展開」を使用して目的の引数を正しく渡す方法
彼の答えでは、davor は、呼び出されたルーチン内でキャレットを 2 倍にする効果を逆にしようとしました。しかし、キャレットが何回倍増したかを確実に知ることができないため、これは信頼できません。代わりに、発信者に通話を調整して補償してもらう方がよいでしょう。それはトリッキーです - あなたは「後期拡張」と呼ばれるものを使用しなければなりません
バッチ スクリプト内で、目的の引数文字列を含む変数を定義し、% を別の % でエスケープして、キャレットが 2 つになるまで展開を遅らせることができます。ステートメント内の各 CALL のパーセントを 2 倍にする必要があります。
@echo off
setlocal
set arg1="blabla,blabla,^>blabla"
call :TEST %%arg1%% "blaby"
echo(
call call :TEST %%%%arg1%%%% "blaby"
::unquoted test
exit /b
:TEST
setlocal
set list=%~1
echo "LIST: %list%"
echo "ARG 1: %~1"
echo "ARG 2: %~2"
exit /b
上記により、目的の結果が生成されます。
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
コマンドラインから実行する場合、展開規則は異なります。コマンド ラインから % をエスケープすることはできません。代わりに、展開フェーズが最初のパスで名前を認識しないようにするパーセント内にキャレットを追加する必要があります。その後、フェーズ 2 でキャレットが取り除かれると、展開の 2 回目のパスで変数が適切に展開されます。
以下はdavor独自のTEST.BATを使用
C:\test>test.bat "blabla,blabla,^>blabla" "blaby"
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
C:\test>set arg1="blabla,blabla,^>blabla"
C:\test>test.bat %arg1% "blaby"
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
C:\test>call test.bat %^arg1% "blaby"
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
C:\test>set arg2=%^arg1%
C:\test>call call test.bat %^arg2% "blaby"
"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"
エスケープの代替手段 - 参照渡しで値を渡す!
全体として、エスケープ ルールはとてつもなく複雑です。そのため、高度なバッチ スクリプトでは、多くの場合、文字列値をリテラルとしてではなく参照によって渡します。目的の文字列が変数に配置され、変数の名前が引数として渡されます。遅延展開は、特殊文字や CALL キャレットの二重化、パーセント除去による破損を恐れずに、正確な文字列を取得するために使用されます。
これは、概念を示す簡単な test.bat です。
@echo off
setlocal enableDelayedExpansion
set "var1=!%~1!"
echo var1=!var1!
call :test var1
exit /b
:test
set "var2=!%~1!"
echo var2=!var2!
そして、これがどのように機能するかのデモンストレーションです。
C:\test>set complicatedString="This & that ^" ^& the other thing ^^ is 100% difficult to escape
C:\test>set complicatedString
complicatedString="This & that ^" & the other thing ^ is 100% difficult to escape
C:\test>test.bat complicatedString
var1="This & that ^" & the other thing ^ is 100% difficult to escape
var2="This & that ^" & the other thing ^ is 100% difficult to escape
C:\test>call test.bat complicatedString
var1="This & that ^" & the other thing ^ is 100% difficult to escape
var2="This & that ^" & the other thing ^ is 100% difficult to escape
C:\test>call call test.bat complicatedString
var1="This & that ^" & the other thing ^ is 100% difficult to escape
var2="This & that ^" & the other thing ^ is 100% difficult to escape