eplawless自身の答えは彼の特定の問題を簡単かつ効果的に解決します:"
引数リスト全体のすべてのインスタンスをで置き換えます\"
。これは、Bashが二重引用符で囲まれた文字列内の二重引用符を表すために必要な方法です。
Windowsコマンドラインインタープリターを使用して、二重引用符で囲まれた文字列内の二重引用符をエスケープする方法cmd.exe
の質問に一般的に答えるために(コマンドラインで-多くの場合、誤って「DOSプロンプト」と呼ばれることがあるか、またはバッチファイルで):PowerShellの概要については、下を参照してください。
tl; dr:
文字列を(他の)に渡すときに使用する必要""
があります、バッチファイル、あなたは可能使用""
して作成されたアプリケーションと、マイクロソフトのC / C ++ / NETコンパイラ。(も受け入れる\"
Windows上で)、 PythonとのNode.jsを含み:
\"
が必要です -唯一のオプションとして-他の多くのプログラム(たとえば、Ruby、Perl、さらにはMicrosoft独自のWindows PowerShell(!))でも必要ですが、その使用は安全ではありません。
\"
多くの実行可能ファイルとインタープリター(Windows PowerShellを含む)に外部から文字列を渡すときに必要なものです。または、Microsoftのコンパイラーの ""
場合は、代替としてサポート -最終的に、引数リストを解析するのはターゲットプログラム次第です。
- 例:
foo.exe "We had 3\" of rain."
- しかし、の使用
\"
不要な、任意のコマンドの実行および/またはINPUT / OUTPUTのリダイレクトでできる結果:
- 次の文字がこのリスクを示しています。
& | < >
- たとえば、次の場合、
ver
コマンドが意図せずに実行されます。説明と回避策の次の箇条書きについては、以下を参照してください。
foo.exe "3\" of snow" "& ver."
- 以下のためのWindows PowerShell、
\""
および"^""
堅牢であるが、限られた選択肢(以下「PowerShellののCLIを...呼び出し」を参照してください)。
を使用する必要がある場合\"
、安全なアプローチは3つしかありませんが、これは非常に面倒です。TSの助けのためのヒント
バッチファイルで(場合によっては選択的な)遅延変数展開を使用して、リテラル\"
を変数に格納し、構文"..."
を使用してその変数を文字列内で参照できます!var!
。TSの役立つ回答を参照してください。
- 上記のアプローチは、面倒ではありますが、系統的に適用でき、堅牢に機能するという利点があります、あらゆる入力に。
リテラル文字列(変数を含まない文字列)を使用した場合のみ、同様に系統的なアプローチが得られます:カテゴリ別^
cmd.exe
" & | < >
- すべてのメタ文字をエスケープします%
。
foo.exe ^"3\^" of snow^" ^"^& ver.^"
それ以外の場合は、終了区切り文字として誤って解釈されたために、文字列のどの部分が引用符なしであるcmd.exe
と見なされるかを認識することに基づいて、文字列を作成する\"
必要があります。
背景情報については、以下をお読みください。
バックグラウンド
注:これは私自身の実験に基づいています。私が間違っている場合は私に知らせてください。
Unixライクなシステムの BashなどのPOSIXライクなシェルは、引数をターゲットプログラムに個別に渡す前に引数リスト(文字列)をトークン化します。他の拡張の中でも、それらは引数リストを個別の単語に分割(単語分割)し、引用文字を結果の単語(引用の削除)。ターゲットプログラムが渡され、アレイの個々の引数をして、構文の引用符を削除します。
対照的に、Windowsコマンドインタープリターは明らかに引数リストをトークン化せず、引用符を含むすべての引数を含む単一の文字列を渡すだけです。-ターゲットプログラムへ。
ただし、単一の文字列がターゲットプログラムに渡される前にいくつかの前処理が行われます:^
エスケープ文字。二重引用符で囲まれた文字列の外側は削除され(次の文字をエスケープします)、変数参照(たとえば%USERNAME%
)が補間されます最初にます。
したがって、Unixとは異なり、引数文字列を解析し、引用符を削除して個々の引数に分解するのは、解析するのがターゲットプログラムの責任です。このように、異なるプログラムが仮想的に異なる脱出方法を必要とすることができますし、された単一のエスケープ機構もありませんが保証するすべてのプログラムで動作するようには - https://stackoverflow.com/a/4094897/45375は、Windowsのコマンドラインでアナーキーに優れたバックグラウンドが含まれています解析。
\"
上記のように、実際には非常に一般的ですが、安全ではありません。
それcmd.exe
自体はエスケープさ\"
れた二重引用符として認識されないため、コマンドラインで後のトークンを引用符なしとして誤って解釈し、それらをコマンドや入出力リダイレクトとして解釈する可能性があります。一言で言えば、次のいずれかの文字が続く場合、問題は、表面開口またはアンバランスを:。例えば:
\"
& | < >
foo.exe "3\" of snow" "& ver."
cmd.exe
は、\"
通常の二重引用符として誤って解釈した結果として、次のトークンを表示します。
"3\"
of
snow" "
- 残り:
& ver.
は引用符で囲まれていcmd.exe
ないと考えるので、それ& ver.
は(コマンドシーケンス演算子)として解釈され、その後に実行するコマンドの名前が続きます(- は無視されます。バージョン情報を報告します)。
全体的な効果は次のとおりです。&
ver.
.
ver
cmd.exe
- 最初に、
foo.exe
最初の3つのトークンのみで呼び出されます。
- その後、コマンド
ver
が実行されます。
偶発的なコマンドが害を及ぼさない場合でも、すべての引数がコマンドに渡されるわけではないため、コマンド全体が設計どおりに機能しません。
多くのコンパイラー/インタープリター\"
は、GNU C / C ++コンパイラー、Python、Perl、Ruby、さらにはMicrosoft独自のWindows PowerShellから呼び出された場合にのみ認識しますcmd.exe
-そして(制限付きで)Windows PowerShellを除いて\""
、単純な解決策はありませんこの問題に。
基本的に、コマンドラインのどの部分が引用符で囲まれていないと誤って解釈されているかを事前に把握し、それらの部分の^
すべてのインスタンスを選択的にエスケープする必要があります& | < >
。
これとは対照的に、の使用は""
安全ですが、されて残念ながら唯一のMicrosoftコンパイラベースの実行可能ファイルおよびバッチファイルでサポートされている(癖は、上述し、バッチファイルの場合)、これは注目すべき除外PowerShellは -次のセクションを参照してください。
cmd.exe
またはPOSIXのようなシェルからPowerShellのCLIを呼び出す:
注:PowerShell 内での引用の処理方法については、下のセクションを参照してください。
呼び出されたときに外部から -例えば、からcmd.exe
、どうか、コマンドラインまたはバッチファイルから:
PowerShell [コア] v6 +は""
(に加えて\"
)を正しく認識するようになりました。これは安全に使用でき、空白を保持します。
pwsh -c " ""a & c"".length "
壊れず、正しく降伏する 6
Windows PowerShell(最後のバージョンが5.1であるレガシーエディション)は 、Windowsでもより堅牢な/ のみを認識します \"
"""
\""
"^""
(PowerShellは内部`
的に二重引用符で囲まれた文字列のエスケープ文字として使用され、受け入れられ""
ますが、下のセクションを参照してください)。
バッチファイルからWindows PowerShell をcmd.exe
呼び出す:
""
基本的にサポートされていないため、 breaks:
powershell -c " ""ab c"".length "
->エラー「文字列にターミネータがありません」
\"
と原則的に"""
動作しますが、安全ではありません:
powershell -c " \"ab c\".length "
意図したとおりに機能します:出力します5
(2スペースに)
- ので、しかし、それは、安全ではありません
cmd.exe
。エスケープしない限り、メタ文字は、コマンドを破る
powershell -c " \"a& c\".length "
休憩のためには、&
のようにエスケープする必要があろう、^&
\""
で安全な、しかしノーマライズインテリア空白望ましくないことができます:
powershell -c " \""a& c\"".length "
4
2つのスペースが1に正規化されているため、出力(!)
"^""
Windows PowerShellの場合、特に安全で空白を維持するのに最適ですが、PowerShell Core(Windows)ではと同じ\""
です。つまり、空白を正規化します。このアプローチを発見したことはVenryxの功績です。
上のUnixライクなプラットフォーム(Linuxでは、MacOSの)、呼び出し[コア] PowerShellをのCLIを、pwsh
、よりPOSIXに似た殻のようなbash
:
を使用する必要\"
がありますが、これは安全であり、空白を保持します。
$ pwsh -c " \"a& c|\".length" # OK: 5
関連情報
^
二重引用符で囲まれた文字列内- 引用符で囲まれていない文字列のエスケープ文字としてのみ使用できます^
は、特別はなくリテラルとして扱われます。
- 警告:ステートメントに渡されたinパラメータの使用は壊れています
^
call
(これは、call
別のバッチファイルまたはバイナリの呼び出しと同じバッチファイル内のサブルーチンの呼び出しのます):
^
二重引用符で囲まれた値のインスタンスは、不可解に二重化され、渡される値が変更されます。たとえば、変数%v%
にリテラル値が含まれている場合a^b
、サブルーチンの(最初のパラメーター)に(!)をcall :foo "%v%"
割り当てます。"a^^b"
%1
:foo
- 引用符で囲まれていないの使用
^
とcall
されて完全に壊れたという点では、^
もはや特殊文字をエスケープするために使用することはできません。例えば、call foo.cmd a^&b
静かに(代わりにリテラル渡すの休憩a&b
すぎfoo.cmd
ずに場合のように、call
) -foo.cmd
でも呼び出されることはありません、少なくともWindows上で(!) 7。
リテラルのエスケープすることは%
特殊なケースでいる、残念ながら、文字列が上で指定されているかどうかに応じて、個別の構文を必要とコマンドライン対バッチファイル内。https://stackoverflow.com/a/31420292/45375を参照してください
- 短い説明:バッチファイル内では、を使用します
%%
。コマンドラインで%
はエスケープできませんが^
、引用符で囲まれていない文字列(例:)内の変数名の先頭、末尾、または内部にa echo %^foo%
を配置すると、変数の展開(補間)を防ぐことができます。%
変数参照の一部ではないコマンドラインのインスタンスは、リテラルとして扱われます(例:)100%
。
一般に、スペースや特殊文字を含む可能性のある変数値を安全に操作するには、次のようにします。
- 割り当て:変数名と値の両方を1組の二重引用符で囲みます。たとえば、
set "v=a & b"
リテラル値a & b
を変数に割り当てます%v%
(対照的にset v="a & b"
、二重引用符を値の一部にします)。リテラル%
インスタンスをエスケープします%%
(バッチファイルでのみ機能します-上記を参照)。
- 参照:変数参照を二重引用符で囲んで、値が補間されないようにします。たとえば、
echo "%v%"
の値%v%
を補間および印刷しません"a & b"
(ただし、二重引用符も常に印刷されることに注意してください)。対照的に、echo %v%
はリテラルa
をに渡し、コマンドシーケンス演算子としてecho
解釈&
するため、というコマンドを実行しようとしb
ます。
また^
、call
ステートメントでの上記の再利用に関する注意事項にも注意してください。
- 外部プログラムは通常のパラメータの周りに二重引用符を囲む削除の世話をする、しかし、述べたように、バッチファイルで使用するには、(例えば、それを自分で行う必要がある
%~1
第一のパラメータから二重引用符を囲む削除する)と、悲しいことに、何ら直接的なはありません二重引用符を囲まずにecho
変数値を忠実に出力する方法を私は知っています。
- Neilは、値に二重引用符が埋め込まれていない限り機能する、
for
ベースの回避策を提供します。例えば:
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
単一引用符を文字列区切り文字として認識しません -それらはリテラルとして扱われ、通常、埋め込まれた空白で文字列を区切るために使用することはできません。また、単一引用符に隣接するトークンとその間のトークンは、によって引用されていないものとして扱われcmd.exe
、それに応じて解釈されます。
- ただし、ターゲットプログラムが最終的に独自の引数解析を実行する場合、Rubyなどの一部のプログラムは、Windowsでも単一引用符で囲まれた文字列を認識します。対照的に、C / C ++実行可能ファイル、PerlおよびPythonはそれらを認識しません。
ただし、ターゲットプログラムでサポートされている場合でも、その内容がによる不要な解釈から保護されていないため、一重引用符で囲まれた文字列を使用することはお勧めできませんcmd.exe
。
からの引用 PowerShell 内:
Windows PowerShellは、よりもはるかに高度なシェルでありcmd.exe
、長年Windowsの一部でした(そしてPowerShell Coreは、macOSとLinuxにもPowerShellエクスペリエンスをもたらしました)。
PowerShellは、引用に関して内部的に一貫して機能します。
- 二重引用符で囲まれた文字列内では、
`"
または""
を使用して二重引用符をエスケープします
- 単一引用符で囲まれた文字列内で、単一
''
引用符をエスケープするために使用します
これは、PowerShellコマンドラインで、およびPowerShell 内からPowerShellスクリプトまたは関数にパラメーターを渡すときに機能します。
(としては、PowerShellのに逃げ二重引用符を渡し、上述の外部から必要\"
、それ以上のこと\""
です。
呼び出すときに悲しいことに、外部のPowerShellからプログラムを、あなたは両方のPowerShell独自の引用規則に対応する必要性に直面しているとのために脱出するために、ターゲットプログラム:
この問題のある動作についても、この回答で説明および要約されています
double内の二重引用符引用符で囲まれた文字列引用符:
文字列を検討 "3`" of rain"
PowerShellが内部的にリテラルに変換する3" of rain
。
この文字列を外部プログラムに渡す場合は、PowerShell に加えて、ターゲットプログラムのエスケープを適用する必要があります。文字列をCプログラムに渡したいとします。これは、埋め込まれた二重引用符が次のようにエスケープされることを期待します\"
。
foo.exe "3\`" of rain"
どのようにノートの両方が、 `"
PowerShellを幸せにする- - と\
-ターゲットプログラムを幸せにするために-存在している必要があります。
同じロジックが、""
使用する必要があるバッチファイルの呼び出しにも適用されます。
foo.bat "3`"`" of rain"
対照的に、二重引用符で囲まれた文字列に単一引用符を埋め込む場合、エスケープはまったく必要ありません。
単一引用符で囲まれた文字列内の単一引用符は、余分なエスケープを必要としません。PowerShellによるの表現であるを検討してください。'2'' of snow'
2' of snow
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShellは、単一引用符で囲まれた文字列を、二重引用符で囲まれた文字列に変換してから、ターゲットプログラムに渡します。
ただし、PowerShellでエスケープする必要がない一重引用符で囲まれた文字列内の二重引用符は、ターゲットプログラムでもエスケープする必要があります。
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShellのv3は魔法の導入--%
オプションと呼ばれ、ストップ・パースのシンボル、それは後に何かを渡すことによって、痛みの一部を緩和し、未解釈のために保存し、ターゲットプログラムにcmd.exe
スタイルの環境変数の参照(例えば、%USERNAME%
)、されている拡張され、例えば:
foo.exe --% "3\" of rain" -u %USERNAME%
ターゲットプログラムの場合のみ(PowerShellの場合も同様)ではなく、埋め込み"
をエスケープする\"
だけ\`"
で十分であることに注意してください。
ただし、このアプローチ:
- 環境変数の展開を回避するために、文字をエスケープ することはできません
%
。
- PowerShell変数と式を直接使用できません。代わりに、コマンドラインは最初のステップで文字列変数に組み込まれ、次に
Invoke-Expression
2番目のステップで呼び出される必要があります。
このように、PowerShellは多くの進歩にもかかわらず、外部プログラムを呼び出すときにエスケープをはるかに簡単にしていません。ただし、単一引用符で囲まれた文字列のサポートが導入されています。
私はそれがさせるのUnixのモデルに、これまでのスイッチに、Windowsの世界では基本的に可能ですかしらシェルは、すべてのトークン化と引用除去を行う予想通り、フロントまで、関係なく、ターゲットプログラムのターゲットプログラム呼び出したトークンを渡すことによって、および。