Windows命令解释器(CMD.EXE)如何解析脚本?

34 浏览
0 Comments

Windows命令解释器(CMD.EXE)如何解析脚本?

我发现了ss64.com,它提供了如何编写Windows命令解释器可以运行的批处理脚本的良好帮助。

然而,我一直无法找到一个好的关于批处理脚本语法、如何展开或不展开以及如何转义的解释。

以下是我一直无法解决的一些示例问题:

  • 引号系统是如何管理的? 我编写了一个TinyPerl脚本

    ( foreach $i (@ARGV) { print \'*\' . $i ; } ),编译并调用它的方式是 :

    • my_script.exe \"a \"\"b\"\" c\" → 输出为 *a \"b*c
    • my_script.exe \"\"\"a b c\"\"\" → 输出为 *\"a*b*c\"
  • 内部echo命令是如何工作的?这个命令里面会展开什么内容?
  • 为什么在文件脚本中要使用for [...]%%I,但在交互式会话中要使用for [...]%I?
  • 转义字符是什么,以及在什么上下文中使用?如何转义百分号?例如,如何对%PROCESSOR_ARCHITECTURE%进行字面量回显? 我发现echo.exe %\"\"PROCESSOR_ARCHITECTURE%可以工作,有更好的方法吗?
  • %的配对是如何匹配的? 示例:

    • set b=a , echo %a %b% c%%a a c%
    • set a =b, echo %a %b% c%bb% c%
  • 如何确保一个变量作为单个参数传递给命令,如果这个变量包含双引号?
  • 当使用set命令时,变量存储在哪里?例如,如果我执行set a=a\" b,然后执行echo.%a%,我会得到a\" b。但如果我使用UnxUtils的echo.exe,我会得到a b。为什么%a%以不同的方式展开?
admin 更改状态以发布 2023年5月21日
0
0 Comments

从命令窗口调用命令时,命令行参数的分词并不是由cmd.exe(也称为“shell”)完成的。大多数情况下,分词是由新形成的进程的C/C++运行时完成的,但这并不一定是这样的情况——例如,如果新进程不是用C/C++编写的,或者如果新进程选择忽略argv并为自己处理原始命令行(例如使用GetCommandLine()),那么分词将不会被完成。在操作系统级别上,Windows将命令行作为未标记为单个字符串传递给新的进程。这与大多数*nix shell不同,在这些shell中,在将参数传递给新形成的进程之前,shell会以一致、可预测的方式对参数进行分词。所有这些意味着,您可能会在Windows上的不同程序之间经历完全不同的参数分词行为,因为个别程序通常会将参数分词交给自己处理。

如果听起来像混乱,它有点像。然而,由于大量的Windows程序确实利用了Microsoft C/C++运行时的argv,因此了解MSVCRT如何分词参数可能是有用的。这里摘录了一部分:

  • 参数由空格或制表符分隔。
  • 由双引号括起来的字符串将被解释为单个参数,不考虑其中包含的空格。引用的字符串可以嵌入到参数中。请注意,插入符(^)不被认为是转义字符或分隔符。
  • 由反斜杠后跟的双引号 (\") 解释为文字双引号 (")。
  • 反斜杠按字面意义解释,除非它们紧接着一个双引号。
  • 如果偶数的反斜杠后跟一个双引号,则在argv数组中为每一对反斜杠()放置一个反斜杠(\),并将双引号(")解释为字符串分隔符。
  • 如果奇数的反斜杠后面跟着一个双引号,则在argv数组中为每一对反斜杠(\)放置一个反斜杠(\),并且剩余的反斜杠将解释为一个转义序列,从而导致将一个文字双引号(")放置在argv中。

Microsoft“批处理语言”(.bat)是这种无政府状态的环境中的一个例外,它已经发展出自己独特的分词和转义规则。看起来cmd.exe的命令提示符确实对命令行参数进行了一些预处理(主要是变量替换和转义),然后将参数传递给新执行的进程。您可以在此页面的jeb和dbenham的优秀答案中了解有关批处理语言和cmd转义的低级详细信息。


让我们在C语言中构建一个简单的命令行实用程序,看看它对您的测试用例有何反应:

int main(int argc, char* argv[]) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("argv[%d][%s]\n", i, argv[i]);
    }
    return 0;
}

(注:argv[0]始终是可执行文件的名称,在下文中为简洁起见省略。在Windows XP SP3上测试。使用Visual Studio 2005编译。)

> test.exe "a ""b"" c"
argv[1][a "b" c]
> test.exe """a b c"""
argv[1]["a b c"]
> test.exe "a"" b c
argv[1][a" b c]

以下是我自己的一些测试:

> test.exe a "b" c
argv[1][a]
argv[2][b]
argv[3][c]
> test.exe a "b c" "d e
argv[1][a]
argv[2][b c]
argv[3][d e]
> test.exe a \"b\" c
argv[1][a]
argv[2]["b"]
argv[3][c]

0
0 Comments

内容太长

0