在 Windows cmd 中,grep 是否使用 GetCommandLine(),而 findstr 是否使用 argv?

在 Windows cmd 中,grep 是否使用 GetCommandLine(),而 findstr 是否使用 argv?

在 Windows cmd 中,grep 是否使用 GetCommandLine(),而 findstr 是否使用 argv?

这是我正在使用的 grep

C:\>where grep
c:\cygwin\bin\grep.exe

C:\>c:\cygwin\bin\grep.exe --version
grep (GNU grep) 3.7
Packaged by Cygwin (3.7-2)
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others; see
<https://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

C:\>

假设我想寻找一条引文。

下面的方法可行,但是有点不正确。

C:\>echo a^"gg|grep "
a"gg

C:\>

它可以工作,但不太正确,因为如果我echo a^"gg|grep " >c:\blah\a.a这样做,它不会生成文件。就像echo ">c:\blah\a.a不会生成文件一样。

它仍然有效,但如果引号后面有其他内容,则可能无效。应该对引号进行转义,以确保 grep 不会只收到引号,而且引号对 cmd 不会具有特殊含义。

C:\>echo a^"gg|grep ^"
a"gg

C:\>

我想确保 grep 没有传递插入符号,因为如果 grep 传递了插入符号,那么它在正则表达式中是有意义的。因此,例如在这两个带有 ^^ 的例子中,grep 传递了一个插入符号。(在正则表达式中,如果字母 z 位于行首,则 ^z 表示匹配)

C:\>echo a^"b | grep ^^a
a"b

C:\>echo a^"b | grep ^^b

C:\>

因此我会记住其中的一些危险。

我注意到

C:\>echo a^"b | grep ^"
a"b

C:\>echo a^"b | findstr \^"
a"b

C:\>

因此 findstr 需要额外的字符 , 来转义引号。

我想知道我们是否可以确定 grep 正在使用 GetCommandLine() 而 findstr 正在使用 argsv。

我所理解的是来自 C 的一个概念。

我有一段时间有这些程序

C:\blah>type w.c
#include <stdio.h>

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

C:\blah>type w2.c
#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[]) {
    printf(GetCommandLine());
    return 0;
}


C:\blah>

Windows 程序可能会加载 windows.h 库,然后它可以使用函数 GetCommandLine() 从命令行获取参数。

另一个选项是 argv 数组,非 Windows 实现会使用,或者 Windows 程序可以使用。参数以数组形式传递给程序的主过程。

因此,无论程序使用的是 GetCommandLine() 还是 argv,我们都可以看到程序所看到的内容。

C:\>w abc def
argv[0] = w
argv[1] = abc
argv[2] = def

C:\>w2 abc def
w2  abc def
C:\>

如果程序使用 GetCommandLine(),那么 ^" 就足以转义引号。

C:\>w2 ^"
w2  "
C:\>

另一方面,如果程序使用 argsv,那么 ^" 不足以转义引号

C:\>echo a^"b | findstr ^"
FINDSTR: No search strings

C:\>echo a^"b | findstr \^"
a"b

C:\>

C:\>w ^"
argv[0] = w
argv[1] =

C:\>w \^"
argv[0] = w
argv[1] = "

C:\>

因此,看起来,如果使用 argv,它只收到一个“,如果在 shell 中写入,它将是 ^”。然后,将其分配给数组的元素,类似于将其分配给变量。它需要用 进行转义。而不是添加 ,它会说无效并删除它。

我认为这可能是正在发生的事情,但我想验证一下这是否正确?

并且纠正一下,windows 实现的 grep 使用 GetCommandLine(),而 findstr 使用 argsv?

添加

回答评论中提出的一个问题,为什么我对应用程序使用的方法感兴趣。例如,也许他们使用了 GetCommandLine() 也许是 CommandLineToArgv() ,我为什么要研究这个?

我对第一阶段使用哪种方法很感兴趣,因为它有助于理解在命令行上给出某些内容时发生了什么,从而更好地理解为什么程序在传递某些内容时会出错的一系列情况。例如,在理解 echo 时,知道它是否使用或似乎使用 GetCommandLine() 会很有帮助,因为我可以有一个使用 GetCommandLine() 的程序来显示它所看到的内容,尤其是当你有一个像 grep 这样的程序可以为正则表达式解释某些内容时,它确实有助于了解它首先收到什么以及它在开始时如何将其分解为 argsv 以及它是否这样做。然后程序变得更容易使用。并且当人们知道它在开始时以这种方式解析的方法时(可以在我在问题中提到的 wc 或 w2.c 等程序中看到),那么理解和记住它/语法也会更容易。

答案1

您正在使用 Cygwin grep,它是基于移植到 Windows 的 Linux 库构建的。

它不使用GetCommandLine,正如你在搜索时看到的那样 Grep 3.7 源代码

findstr本身是Windows的一部分,是专有代码,所以我们无法知道它使用了什么。

答案2

所有 Windows 进程都只能获得一个字符串作为其命令行,因此通常它们必须使用 GetCommandLine()一些点并将其解析为参数(或不解析)。即使您的程序有 ,情况也是如此main(argc, argv),因为 main() 不是可执行文件的真正“入口点”——实际上是 C 运行时库(例如 msvcrt 1)首先被调用,并在调用 main() 之前将接收到的命令行解析为 argv[]。

通过 Cygwin 提供的软件的工作方式相同 - Cygwin grep 或多或少是对原始面向 Linux/Unix 的源代码的直接重新编译,它依赖于main(argc, argv)。但在这种情况下,它是 Cygwin 运行时 (cygwin1.dll),其dll_crt0_1()入口点函数执行此转换

(此命令行到 argv 的转换也是 Windows MSVCRT 扩展文件通配符(globs)的地方,也是 Cygwin 将 Windows 样式的路径转换为 ​​Cygwin 样式的路径的地方。)

因此,GNU grep(即 Cygwin 中所拥有的)和 Windows findstr.exe 1实际上具有相同的类型main(argc, argv),并且它们都没有明确调用 GetCommandLine() - 它们都依赖于相应的 C 运行时库来执行此操作......但方式不同。


1我检查了去年泄露的NT5源代码中的findstr.c。

2 msvcrt 的源代码是实际上如果我没记错的话,它应该在某个公共的地方,但我不确定它应该在哪里找到。它可能是 Windows SDK 的一部分,也许?

相关内容