2011-06-21 6 views
6

私は文字列のリストを持っており、それらの文字列を1つのWindowsコマンドライン呼び出しで引数として渡したいと思います。シンプルな英数字の文字列の場合はそれだけでそのまま渡すすればよい:Windowsでコマンドライン引数として使用するために任意の文字列をエスケープするにはどうすればよいですか?

> script.pl foo bar baz yes no 
foo 
bar 
baz 
yes 
no 

私は、引数にスペースまたは二重引用符が含まれている場合、私は二重引用符やバックスラッシュ、その後、二重引用符をバックスラッシュでエスケープする必要があることを理解議論。

> script.pl foo bar baz "\"yes\"\\\"no\"" 
foo 
bar 
baz 
"yes"\"no" 

しかし、私はリテラルパーセント記号で引数を渡すしようとすると、この問題が発生した:

> script.pl %PATH% 
C:\Program 
Files\PHP\;C:\spaceless\perl\bin\;C:\Program 
Files\IBM\Java60\bin; 
(...etc.) 

はダブル動作しません引用:

> script.pl "%PATH%" 
C:\Program Files\PHP\;C:\spaceless\perl\bin\;C:\Program Files\IBM\Java60\bin; (...etc.) 

もバックスラッシュエスケープん(出力にバックスラッシュがどのように存在するかを確認してください)。

> script.pl \%PATH\% 
\%PATH\% 

また、ルールはバックスラッシュ・エスケープバックスラッシュのために矛盾しています:

> script.pl "\\yes\\" 
\\yes\ 
> script.pl "\yes\\" 
\yes\ 
> script.pl "\yes\" 
\yes" 

はまた、確かに特殊文字はすべてのシェルである多くのと同じように、Windowsのコマンドラインシェルであります。 それでは、Windowsのコマンドラインで使用するために任意のコマンドライン引数を安全にエスケープする一般的な手順は何ですか?

理想的な答えは、次のような状況で使用することができる機能escape()(Perlの例)について説明します。ここでは

$cmd = join " ", map { escape($_); } @args; 

は(安全に、この関数でエスケープされなければならないいくつかのより多くの例の文字列です私はこれらのいくつかがUnixのように見えますが、それは意図的です):

yes 
no 
child.exe 
argument 1 
Hello, world 
Hello"world 
\some\path with\spaces 
C:\Program Files\ 
she said, "you had me at hello" 
argument"2 
\some\directory with\spaces\ 
" 
\ 
\\ 
\\\ 
\\\\ 
\\\\\ 
"\ 
"\T 
"\\T 
!1 
!A 
"!\/'" 
"Jeff's!" 
$PATH 
%PATH% 
& 
<>|&^ 
()%!^"<>&| 
>\\.\nul 
malicious argument"&whoami 
*@[email protected]#?-_ 

答えて

3

ここにmsdnのblogpostが表示されています。ただし、すべてのコマンドラインプログラムは、内部でCommandLineToArgvWを使用してコマンドラインを解析していることを前提としています(Shell32ライブラリの一部であるため、控えめではありません)。

http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx

+0

は、この非常に有益なリンクをありがとうございました。私の質問は今答えられています。 – qntm

+0

もちろん、これはコマンドライン引数を扱うように見えます。 '^" C:\ Program Files \ p.pl^"yields" "C:\ Program"が認識されないという同じ手順が、最初の引数、すなわち起動するプログラムの名前をエスケープするためには機能していないようです。任意のアイデアですか? – qntm

+0

http://support.microsoft.com/kb/103368のように見えますが、正しい答えが得られます。ファイル名に '|'は使用できません。 – qntm

4

次を使用し、コマンドライン引数をエスケープする:

sub escapeArg { 
    my $arg = shift; 

    # Sequence of backslashes followed by a double quote: 
    # double up all the backslashes and escape the double quote 
    $arg =~ s/(\\*)"/$1$1\\"/g; 

    # Sequence of backslashes followed by the end of the arg, 
    # which will become a double quote later: 
    # double up all the backslashes 
    $arg =~ s/(\\*)$/$1$1/; 

    # All other backslashes do not need modifying 

    # Double-quote the whole thing 
    $arg = "\"".$arg."\""; 

    # Escape shell metacharacters 
    $arg =~ s/([()%!^"<>&|;, ])/\^$1/g; 

    return $arg; 
} 

、このようなばかげ名を指定してコマンドを呼び出すときに、たとえば、実際のコマンドラインコマンドを脱出するには()!&%PATH%^;, .exe(これは完全に合法です)として、以下を使用してください:

sub escapeCmd { 
    my $arg = shift; 

    # Escape shell metacharacters 
    $arg =~ s/([()%!^"<>&|;, ])/\^$1/g; 
    return $arg; 
} 

コマンドにescapeArg()を使用すると機能しません。

出典:

+0

'$ arg'に空白が含まれていない場合は、技術的に二重引用符で' $ arg'を囲む必要はありません(末尾のバックスラッシュの数を2倍にする必要があります)。[C++コマンドライン引数の解析](http://msdn.microsoft.com/en-us/library/17w5ykft.aspx)。私はあなたがシェルのメタキャラクタをエスケープする必要があるとも信じていません。たとえば、コマンドラインを 'CreateProcess'と' (バッチファイルや 'cmd/c' /' cmd/k'の引数のために)あなたがシェルメタキャラクタをエスケープする必要がある。) – vladr

関連する問題