7

実行するとしますtest.bat "blabla,blabla,^>blabla", "blaby"

test.bat の実装:

@SETLOCAL
@ECHO OFF
SET list=%~1
ECHO "LIST: %list%"
ECHO "ARG 1: %~1"
ECHO "ARG 2: %~2"
@ENDLOCAL   
@GOTO :EOF

出力は期待どおりです。

"LIST: blabla,blabla,>blabla"
"ARG 1: blabla,blabla,^>blabla"
"ARG 2: blaby"

しかし、test.bat をバッチ ファイル内の関数にするとどうなるでしょうか。

@SETLOCAL
CALL :TEST "blabla,blabla,^>blabla", "blaby"
@ENDLOCAL
@GOTO :EOF

:TEST
@SETLOCAL
@ECHO OFF
SET list=%~1
ECHO "LIST: %list%"
ECHO "ARG 1: %~1"
ECHO "ARG 2: %~2"
@ENDLOCAL   
@GOTO :EOF

実行後の出力は次のとおりです。

"LIST: blabla,blabla,^"
"ARG 1: blabla,blabla,^^>blabla"
"ARG 2: blaby"

は?

  1. blablaLISTのどこに行きましたか?
  2. ARG 1 には^^? なんで?

コマンドライン引数とは対照的に、関数引数で特殊文字の動作がどのように異なるかを誰かが説明できますか?

4

2 に答える 2

10

次を使用するだけで、最初のバッチ スクリプトで同じ結果を得ることができます。

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
于 2012-09-29T21:50:36.737 に答える
0

いくつかのテストと dbenham の回答の後、ダブル キャレットを予期してシングル キャレットに戻す必要があることがわかります。

@SETLOCAL
CALL :TEST "blabla,blabla,^>blabla", "blaby"
@ENDLOCAL
@GOTO :EOF

:TEST
@SETLOCAL
@ECHO OFF
SET "list=%~1" & REM CHANGED
SET "list=%list:^^=^%" & REM ADDED
ECHO "LIST: %list%"
ECHO "ARG 1: %~1"
ECHO "ARG 2: %~2"
@ENDLOCAL   
@GOTO :EOF

出力は次のとおりです。

"LIST: blabla,blabla,^>blabla"
"ARG 1: blabla,blabla,^^>blabla"
"ARG 2: blaby"

奇妙なことにも注意してください: in SET "list=%list:^^=^%"the ^^between%%は、エスケープされた としてではなく、2 つの文字として扱われ^ます。

于 2012-09-30T14:39:34.463 に答える