8

我有一个 C# 命令行应用程序,我需要在 windows 和 unix 的 mono 下运行。在某些时候,我想在给定一组通过命令行传入的任意参数的情况下启动一个子进程。例如:

Usage: mycommandline [-args] -- [arbitrary program]

不幸的是,System.Diagnostics.ProcessStartInfo 只接受一个字符串作为参数。这是诸如以下命令的问题:

./my_commandline myarg1 myarg2 -- grep "a b c" foo.txt

在这种情况下,argv 看起来像:

argv = {"my_commandline", "myarg1", "myarg2", "--", "grep", "a b c", "foo.txt"}

请注意,“ab c”周围的引号被外壳剥离,所以如果我简单地连接参数以便为 ProcessStartInfo 创建 arg 字符串,我会得到:

args = "my_commandline myarg1 myarg2 -- grep a b c foo.txt"

这不是我想要的。

是否有一种简单的方法可以将 argv 传递给 C# 下的子进程启动,或者将任意 argv 转换为对 windows 和 linux shell 合法的字符串?

任何帮助将不胜感激。

4

5 回答 5

1

MSDN 描述了 MS Visual C 运行时如何将返回的字符串解析GetCommandLine()argv数组。

您可能还对Python模块用于模拟 Win32 环境中的 Unix行为list2cmdline()的 Python 标准库中的函数感兴趣。subprocessargv

于 2010-06-02T19:06:51.920 回答
1

在 windowsland 中,真的很简单...在传递给 System.Diagnostics.ProcessStartInfo 对象的字符串中添加额外的引号。

例如 "./my_commandline" "myarg1 myarg2 -- grep \"abc\" foo.txt"

于 2010-06-03T15:45:48.693 回答
1

感谢大家的建议。我最终使用了来自 shquote ( http://www.daemon-systems.org/man/shquote.3.html ) 的算法。

/**
 * Let's assume 'command' contains a collection of strings each of which is an
 * argument to our subprocess (it does not include arg0).
 */
string args = "";
string curArg;
foreach (String s in command) {
    curArg = s.Replace("'", "'\\''"); // 1.) Replace ' with '\''
    curArg = "'"+curArg+"'";          // 2.) Surround with 's
    // 3.) Is removal of unnecessary ' pairs. This is non-trivial and unecessary
    args += " " + curArg;
}

我只在linux上测试过这个。对于 Windows,您只需连接 args。

于 2010-06-03T17:53:41.850 回答
0

grep您将需要使用所有需要的参数来运行一个新的子进程grep

void runProcess(string processName, string args)
{
    using (Process p = new Process())
    {
        ProcessStartInfo info = new ProcessStartInfo(processName);
        info.Arguments = args;
        info.RedirectStandardInput = true;
        info.RedirectStandardOutput = true;
        info.UseShellExecute = false;
        p.StartInfo = info;
        p.Start();
        string output = p.StandardOutput.ReadToEnd();
        // process output
    }
}

然后打电话给runProcess("grep", "a", "b", "c", "foo.txt");

编辑:更新 args 处理。

于 2010-06-02T18:20:54.590 回答
0

只需使用正则表达式来检查字符串是否包含任何类型的空格,然后用带引号的新字符串替换原始字符串:

using System.Text.RegularExpressions;
// ...
for(int i=0; i<argv.Length; i++) {
    if (Regex.IsMatch(i, "(\s|\")+")) {
        argv[i] = "\"" + argv[i] + "\"";
        argv[i].Replace("\"", "\\\"");
    }
}
于 2010-06-03T10:39:29.953 回答