如何正确地将命令行参数传递给Windows应用程序?

3
在Linux中,使用exec*命令将命令行参数传递给应用程序非常简单,您只需明确地传递每个参数即可。但是,在Windows上使用相同的函数进行此操作并不可取,如果想要控制标准管道的话。由于这些函数基于CreateProcess(),因此需要遵循一些明确的规则来转义特殊字符(如双引号)。
不幸的是,只有当被调用的应用程序通过main()、wmain()或CommandLineToArgvW()获取其命令行参数时,才能正确地工作。然而,如果被调用的应用程序通过WinMain()、wWinMain()、GetCommandLineA()或GetCommandLineW()获取这些参数,则由应用程序解析命令行参数的方式取决于它获得整个命令行而不是逐个参数。
这意味着一个名为test的简单应用程序,使用main()作为入口点,如果被称为test.exe \"abc\",则会得到"abc"。如果将cmd.exe称为cmd.exe /c "echo \"abc\"",则不会像预期的那样输出"abc",而是\"abc\"。
这就引出了我的问题:
尽管存在这些怪癖,如何以通用的方式传递命令行参数给Windows应用程序?

只要应用程序可以自由地解析命令行,那么从定义上来说就没有通用的方式来发送参数。您有任何特定的问题需要解决吗?您需要通用解决方案来做什么? - Karel Petranek
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - IInspectable
你链接的规则参考是描述Microsoft运行库如何解析参数的。我认为CommandLineToArgvW有些不同。无论如何,API级别没有这些规则。在Windows中,引用的常见约定除了基本的双引号字符外,没有其他。当你将文件拖到可执行文件上时,常见的GUI shell只是引用它们(你可以尝试一下,看看如何传递它们)。 - Cheers and hth. - Alf
我正在尝试编写一个应用程序,例如在用户定义的 shell 中运行命令。因此,由用户来执行在 cmd.exe 或 sh.exe(例如来自 Cygwin 或 MSys)中的 echo "abc"。我正在读取执行应用程序的输出以进行进一步处理。 - user2525536
你似乎将命令行解释器的解析与应用程序的解析混淆了。看起来你将命令行解释器的解析归因于应用程序。除非你提供一个简明扼要的规范说明你真正想要什么,以及为什么它没有展现出预期的行为,否则这个问题是不相关的,并且可能会被关闭。 - IInspectable
这意味着如果我不确切知道应用程序的命令行解析器如何工作,以便我可以引用特殊字符,那么我就无法将例如参数abc\"xyz传递给任何应用程序,并保留所有字符完全按照给定的方式。 - user2525536
2个回答

0

在C语言中,需要在双引号前使用反斜杠。但是,在shell处理中没有这样的规则。因此,如果您编写调用CreateProcess并传递字面字符串"abc"的代码,则需要使用反斜杠,因为您正在使用C语言编写。但是,如果您编写一个shell脚本来调用您的应用程序以传递"abc",例如Echo示例,则不需要使用反斜杠,因为没有涉及C代码。


0
在Windows中,您需要将命令视为一个整体,而不是一系列单独的参数。应用程序没有义务以任何特定方式解析命令成为参数,或者根本不解析;考虑echo命令的例子,它将命令行视为单个字符串。
这可能会给运行时库开发人员带来问题,因为这意味着没有可靠的方法来实现类似POSIX的exec函数。一些库开发人员采取直接的方法,要求程序员根据需要提供引号,而有些则尝试自动引用参数。在后一种情况下,必须提供某种方法让程序员指定整个命令行,禁用任何自动引用,即使这意味着使用Windows特定的扩展。
然而,在您的场景中(如评论中所述),不应该存在问题。您需要做的就是确保向用户询问命令,而不是一系列参数。如果您的程序完全不需要知道命令将如何分割成参数,甚至不需要了解命令的语法,这是用户的工作。[注:如果您认为这不正确,您需要更清楚地解释您的场景。提供用户可能输入的示例以及您认为应用程序需要如何处理它的方式。]

PS:由于您提到了C库的_exec函数,请注意它们的工作方式可能与您期望的不同。参数不会单独传递给子进程,因为这是不可能的;在Microsoft C运行时中,如果我没记错的话,参数只是简单地组合成一个字符串,以单个空格作为分隔符,因此("hello there")将无法与("hello", "there")区分。

PPS:请注意,调用cmd.exe来解析命令会引入一个额外(且更复杂)的处理层。一般来说,考虑到这一点仍然是用户的工作,但您可能需要意识到它。对于cmd.exe处理的转义字符是插入符号。


我早已猜到了,但我接受这个答案,因为它证实了我所想的:在Windows中没有通用的方法可以保留所有字符并仍将参数逐个传递给不同的应用程序与Linux一样,因为Windows在这部分的工作方式上有根本的不同。我将让用户提供正确的引用方案。我还需要用户提供可执行文件的路径,因为如果我想支持cmd.exe和co.,则无法自动检索CreateProcess()。 - user2525536

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接