1. ホーム
  2. c#

c#でコマンドライン引数をエスケープする

2023-10-23 04:29:10

質問

短いバージョンです。

引数を引用符で囲み、エスケープすることで十分なのでしょうか? \" ?

コードバージョン

コマンドライン引数を渡したい string[] args を、ProcessInfo.Arguments を使用して別のプロセスに渡したい。

ProcessStartInfo info = new ProcessStartInfo();
info.FileName = Application.ExecutablePath;
info.UseShellExecute = true;
info.Verb = "runas"; // Provides Run as Administrator
info.Arguments = EscapeCommandLineArguments(args);
Process.Start(info);

問題は、引数を配列として受け取り、それらを単一の文字列に結合しなければならないことです。引数は、私のプログラムを騙すために細工することができます。

my.exe "C:\Documents and Settings\MyPath \" --kill-all-humans \" except fry"

によると この回答 引数1つをエスケープするために以下のような関数を作成したのですが、何か見落としがあったかもしれません。

private static string EscapeCommandLineArguments(string[] args)
{
    string arguments = "";
    foreach (string arg in args)
    {
        arguments += " \"" +
            arg.Replace ("\\", "\\\\").Replace("\"", "\\\"") +
            "\"";
    }
    return arguments;
}

これでいいのか、それとも何かフレームワークの機能があるのでしょうか?

どのように解決するのですか?

もっと複雑なんだけどね。

私は関連した問題(渡されたすべてのパラメータといくつかの余分なものを持つバックエンドを呼び出すフロントエンド.exeを書く)を持っていたので、私は人々がそれを行う方法を調べ、あなたの質問に遭遇した。当初は、あなたが提案するようにそれを行うことはすべて良いように見えました。 arg.Replace (@"\", @"\\").Replace(quote, @"\"+quote) .

しかし、引数で呼び出すと c:\temp a\\b として渡されます。 c:\temp そして a\\b で、バックエンドが呼び出されることになります。 "c:\\temp" "a\\\\b" - で呼び出されることになりますが、これは正しくありません。なぜなら、そこには二つの引数 c:\\tempa\\\\b - は、私たちが望んだものではありません! 私たちはエスケープに熱中しすぎました(Windowsはunixではありません!)。

というわけで、詳しく読んでみると http://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs.aspx を読んでみたところ、実際にこれらのケースがどのように扱われるかが書かれていました。 だけです。 として扱われます。

には一工夫あり、複数の \ がどのように扱われるのか、その説明にはしばらくめまいがしそうです。ここで、このアンエスケープ・ルールを言い直してみます。 N \ に続いて " . アンエスケープする場合、その部分文字列を int(N/2) \ で、もし N が変だったので " を追加しています。

このようなデコードのためのエンコーディングは次のようになります: 引数に対して、0以上の部分文字列をそれぞれ見つけて \ の後に " で置き換え、さらにそれを2倍の数の \ で置き換え、その後に \" . というようにすることができます。

s = Regex.Replace(arg, @"(\\*)" + "\"", @"$1$1\" + "\"");

以上...

PS. ... ではなく . 待って、待って - もっとある! :)

エンコーディングは正しく行われましたが、すべてのパラメータをダブルクォートで囲んでいるため、ねじれが生じています (パラメータの一部にスペースがある場合に備えて)。境界の問題があります - パラメータの末尾が \ で終わる場合、パラメータに " を追加すると、引用符で囲んだ意味がなくなります。例 c:\one\ two は、次のように解析されます。 c:\one\ となり two に再アセンブルされ "c:\one\" "two" となり、一つの引数として(誤って)理解されます。 c:\one" two (私はそれを試してみました、私はそれを作っていない)。ですから、私たちが追加で必要とするのは、引数が \ で終わるかどうか、そしてもしそうなら ダブル というように、末尾のバックスラッシュの数を指定します。

s = "\"" + Regex.Replace(s, @"(\\+)$", @"$1$1") + "\"";