如何正确地将命令行参数传递给 Windows 应用程序?
How to pass command-line arguments to a Windows application correctly?
在 Linux 中将命令行参数传递给应用程序与 exec* 命令一起使用效果很好,您可以在其中清楚地单独传递每个参数。如果想要控制标准管道,那么在 Windows 上使用相同的功能这样做不是一种选择。由于这些函数基于 CreateProcess(),因此 are some clear rules 介绍了如何转义双引号等特殊字符。
遗憾的是,这只有在被调用的应用程序通过 main()、wmain() 或 CommandLineToArgvW() 检索其命令行参数时才能正常工作。但是,如果被调用的应用程序通过 WinMain()、wWinMain()、GetCommandLineA() 或 GetCommandLineW() 获取这些参数,则由应用程序决定如何解析命令行参数,因为它获取整个命令行而不是参数按论点。
这意味着使用 main() 作为入口点的名为 test 的简单应用程序如果被调用为 test.exe \"abc\"
将获得 "abc"。将 cmd.exe 调用为 cmd.exe /c "echo \"abc\""
将不会按预期输出 "abc" 而是 \"abc\".
这引出了我的问题:
尽管有这些怪癖,如何以通用方式将命令行参数传递给 Windows 应用程序?
是C语言让你在C代码中双引号前需要使用反斜杠。 shell处理没有这样的规则。因此,如果您编写代码来调用 CreateProcess 并传递文字字符串 "abc"
,那么您需要使用反斜杠,因为您是用 C 编写的。但是如果正在编写 shell 脚本来传递调用您的应用程序以传递 "abc"
,例如Echo 示例,那么您不使用反斜杠,因为不涉及 C 代码。
在 Windows 中,您需要将命令视为一个整体,而不是单个参数的列表。应用程序没有义务以任何特定方式或根本不需要将命令解析为参数;考虑 echo 命令的示例,它将命令行视为单个字符串。
这对于运行时库开发人员来说可能是个问题,因为这意味着没有可靠的方法来实现 POSIX-like exec 函数。一些库开发人员采用直接的方法,并要求程序员在必要时提供引号,有些则尝试自动引用参数。在后一种情况下,必须为程序员提供一些方法来指定整个命令行,禁用任何自动引用,即使这意味着 Windows-specific 扩展。
但是,在您的场景中(如评论中所述)应该没有问题。您所要做的就是确保向用户询问命令,而不是参数列表。您的程序根本 不需要 知道命令将如何拆分为参数,如果有的话;理解命令的语法是用户的工作。 [注意:如果您不认为这是真的,您需要更清楚地解释您的情景。请举例说明用户可能输入的内容以及您认为您的应用程序需要如何处理它。]
PS:既然您提到了 C 库 _exec
函数,请注意它们并不像您预期的那样工作。参数不会单独传递给 child,因为那是不可能的;在 Microsoft C 运行时,如果我没记错的话,参数只是简单地组合成一个字符串,用一个 space 作为分隔符,所以 ("hello there")
与 ("hello", "there")
无法区分。
PPS:请注意,调用 cmd.exe
来解析命令会引入额外的(并且复杂得多)处理层。一般来说,考虑到这一点仍然是用户的工作,但您可能希望了解这一点。 cmd.exe
处理的转义字符是插入符号。
在 Linux 中将命令行参数传递给应用程序与 exec* 命令一起使用效果很好,您可以在其中清楚地单独传递每个参数。如果想要控制标准管道,那么在 Windows 上使用相同的功能这样做不是一种选择。由于这些函数基于 CreateProcess(),因此 are some clear rules 介绍了如何转义双引号等特殊字符。
遗憾的是,这只有在被调用的应用程序通过 main()、wmain() 或 CommandLineToArgvW() 检索其命令行参数时才能正常工作。但是,如果被调用的应用程序通过 WinMain()、wWinMain()、GetCommandLineA() 或 GetCommandLineW() 获取这些参数,则由应用程序决定如何解析命令行参数,因为它获取整个命令行而不是参数按论点。
这意味着使用 main() 作为入口点的名为 test 的简单应用程序如果被调用为 test.exe \"abc\"
将获得 "abc"。将 cmd.exe 调用为 cmd.exe /c "echo \"abc\""
将不会按预期输出 "abc" 而是 \"abc\".
这引出了我的问题:
尽管有这些怪癖,如何以通用方式将命令行参数传递给 Windows 应用程序?
是C语言让你在C代码中双引号前需要使用反斜杠。 shell处理没有这样的规则。因此,如果您编写代码来调用 CreateProcess 并传递文字字符串 "abc"
,那么您需要使用反斜杠,因为您是用 C 编写的。但是如果正在编写 shell 脚本来传递调用您的应用程序以传递 "abc"
,例如Echo 示例,那么您不使用反斜杠,因为不涉及 C 代码。
在 Windows 中,您需要将命令视为一个整体,而不是单个参数的列表。应用程序没有义务以任何特定方式或根本不需要将命令解析为参数;考虑 echo 命令的示例,它将命令行视为单个字符串。
这对于运行时库开发人员来说可能是个问题,因为这意味着没有可靠的方法来实现 POSIX-like exec 函数。一些库开发人员采用直接的方法,并要求程序员在必要时提供引号,有些则尝试自动引用参数。在后一种情况下,必须为程序员提供一些方法来指定整个命令行,禁用任何自动引用,即使这意味着 Windows-specific 扩展。
但是,在您的场景中(如评论中所述)应该没有问题。您所要做的就是确保向用户询问命令,而不是参数列表。您的程序根本 不需要 知道命令将如何拆分为参数,如果有的话;理解命令的语法是用户的工作。 [注意:如果您不认为这是真的,您需要更清楚地解释您的情景。请举例说明用户可能输入的内容以及您认为您的应用程序需要如何处理它。]
PS:既然您提到了 C 库 _exec
函数,请注意它们并不像您预期的那样工作。参数不会单独传递给 child,因为那是不可能的;在 Microsoft C 运行时,如果我没记错的话,参数只是简单地组合成一个字符串,用一个 space 作为分隔符,所以 ("hello there")
与 ("hello", "there")
无法区分。
PPS:请注意,调用 cmd.exe
来解析命令会引入额外的(并且复杂得多)处理层。一般来说,考虑到这一点仍然是用户的工作,但您可能希望了解这一点。 cmd.exe
处理的转义字符是插入符号。