バッチファイルのパラメーター内のすべての二重引用符をエスケープされた二重引用符に置き換えるにはどうすればよいですか?これは現在のバッチファイルで、文字列内のすべてのコマンドラインパラメーターを展開します。
@echo off
call bash --verbose -c "g++-linux-4.1 %*"
次に、その文字列を使用してCygwinのbashを呼び出し、Linuxクロスコンパイラーを実行します。残念ながら、バッチファイルに渡されるこれらのようなパラメーターを取得しています。
"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions
-Wno-inline -Wall -DNDEBUG -c
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o"
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"
渡された最初のパスを囲む最初の引用符は、GCCに渡される文字列を途中で終了し、残りのパラメーターを直接bashに渡すことです(これは見事に失敗します)。
パラメータを単一の文字列に連結し、引用符をエスケープしてうまく機能する場合は想像できますが、これを行う方法を判断するのは困難です。誰か知っている?
Googleは最終的に答えを思いついた。バッチでの文字列置換の構文は次のとおりです。
set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%
「私を複製する」を生成します。スクリプトは次のようになります。
@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"
これにより、"
のすべてのインスタンスが\"
に置き換えられ、bash用に適切にエスケープされます。
バッチスクリプトのエスケープ文字は^
。ただし、二重引用符で囲まれた文字列の場合は、引用符を2重にします。
"string with an embedded "" character"
mklement0の優れた回答 への追加として:
ほとんどすべての実行可能ファイルは_\"
_をエスケープされた_"
_として受け入れます。ただし、cmdでの安全な使用は、DELAYEDEXPANSIONを使用した場合にのみ可能です。
リテラル_"
_を明示的にプロセスに送信するには、_\"
_を環境変数に割り当て、引用符を渡す必要があるときにその変数を使用します。例:
_SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"
_
注_SETLOCAL ENABLEDELAYEDEXPANSION
_は、バッチファイル内でのみ機能するようです。インタラクティブセッションでDELAYEDEXPANSIONを取得するには、_cmd /V:ON
_を起動します。
バッチファイルがDELAYEDEXPANSIONで動作しない場合、一時的に有効にすることができます。
_::region without DELAYEDEXPANSION
SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL
::region without DELAYEDEXPANSION
_
_""
_としてエスケープされた引用符を含む変数から動的コンテンツを渡したい場合、展開時に_""
_を_\"
_に置き換えることができます:
_SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL
_
この置換は_%...%
_スタイルの展開では安全ではありません!
[〜#〜] op [〜#〜] _bash -c "g++-linux-4.1 !v_params:"=\"!"
_の場合は安全なバージョンです。
何らかの理由でDELAYEDEXPANSIONを一時的に有効にすることもオプションではない場合は、以下をお読みください。
Cmd内から_\"
_を使用することは、たまにではなく、常に特殊文字をエスケープする必要がある場合、少し安全です。 (キャレットが一貫していれば、キャレットを忘れる可能性は低くなります...)
これを実現するには、引用符の前にキャレット(_^"
_)を付けます。リテラルとして子プロセスに到達する引用符は、さらにバックスラッシュ(_\^"
_)でエスケープする必要があります。 [〜#〜] all [〜#〜]シェルのメタ文字も_^
_でエスケープする必要があります。 _&
_ => _^&
_; _|
_ => _^|
_; _>
_ => _^>
_;等.
例:
_child ^"malicious argument\^"^&whoami^"
_
ソース: 誰もがコマンドライン引数を間違った方法で引用する 、「引用のより良い方法」を参照
動的コンテンツを渡すには、次のことを確認する必要があります。
変数を含むコマンドの部分は、_cmd.exe
_で「引用」されていると見なされる必要があります(変数に引用符が含まれている場合は不可能です-書かない_%var:""=\"%
_))。これを実現するために、変数の前の最後の_"
_と変数の後の最初の_"
_は_^
_-- escapedではありません。これら2つの_"
_の間のcmdメタ文字はエスケープしないでください。例:
_foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"
_
これは、_%dynamic_content%
_に一致しない引用符を含めることができる場合、安全ではありません。