如何使用 argv 在 C# 中启动子进程? (或者将agrv转换为合法的arg字符串)

发布于 2024-09-04 07:13:00 字数 750 浏览 2 评论 0原文

我有一个 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”周围的引号被 shell 删除,因此如果我只是连接参数以便为 ProcessStartInfo 创建 arg 字符串,我会得到

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

:这不是我想要的。

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

任何帮助将不胜感激。

I have a C# command-line application that I need to run in windows and under mono in unix. At some point I want to launch a subprocess given a set of arbitrary paramaters passed in via the command line. For instance:

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

Unfortunately, System.Diagnostics.ProcessStartInfo only takes a string for args. This is a problem for commands such as:

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

In this case argv looks like :

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

Note that the quotes around "a b c" are stripped by the shell so if I simply concatenate the arguments in order to create the arg string for ProcessStartInfo I get:

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

Which is not what I want.

Is there a simple way to either pass an argv to subprocess launch under C# OR to convert an arbitrary argv into a string which is legal for windows and linux shell?

Any help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

于我来说 2024-09-11 07:13:00

MSDN 有一个关于 MS Visual C 运行时如何解析返回的字符串的描述GetCommandLine()argv 数组。

您可能还对 list2cmdline() 来自 Python 标准库的函数,Python 的 subprocess 模块使用该函数来模拟 Win32 环境中的 Unix argv 行为。

MSDN has a description of how the MS Visual C Runtime parses the string returned by GetCommandLine() into an argv array.

You might also be interested in the list2cmdline() function from the Python standard library that is used by Python's subprocess module to emulate the Unix argv behavior in a Win32 environment.

关于从前 2024-09-11 07:13:00

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

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

In windowsland, it's simple really...add extra quotation marks in the string you pass to the System.Diagnostics.ProcessStartInfo object.

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

久隐师 2024-09-11 07:13:00

感谢大家的建议。我最终使用了 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,您只需连接参数即可。

Thanks to all for the suggestions. I ended up using the algorithm from 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;
}

I've only tested this on linux. For windows you can just concatenate the args.

瑾夏年华 2024-09-11 07:13:00

您将需要使用 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");

编辑:更新了参数处理。

You will need to run a new subprocess using grep and all arguments that grep will be needing.

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
    }
}

then make a call to runProcess("grep", "a", "b", "c", "foo.txt");

Edit: Updated args handling.

江挽川 2024-09-11 07:13:00

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

using System.Text.RegularExpressions;
// ...
for(int i=0; i<argv.Length; i++) {
    if (Regex.IsMatch(i, "(\s|\")+")) {
        argv[i] = "\"" + argv[i] + "\"";
        argv[i].Replace("\"", "\\\"");
    }
}

Just use a Regex to check if a string has spaces of any kind, and replace the original string with a new one with quotes:

using System.Text.RegularExpressions;
// ...
for(int i=0; i<argv.Length; i++) {
    if (Regex.IsMatch(i, "(\s|\")+")) {
        argv[i] = "\"" + argv[i] + "\"";
        argv[i].Replace("\"", "\\\"");
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文