【问题标题】:Why does the file glob **/*.cs in git grep not show me all *.cs hits?为什么 git grep 中的文件 glob **/*.cs 没有显示所有 *.cs 命中?
【发布时间】:2016-11-17 15:43:16
【问题描述】:

所以我想在我的项目中找到 NLog 的使用,我使用 git grep 为我这样做,但它发现了比我需要的更多的案例:

git grep NLog
GETA.Seo.Sitemap/Geta.SEO.Sitemaps.csproj:    <Reference Include="NLog, Version=2.1.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
GETA.Seo.Sitemap/Geta.SEO.Sitemaps.csproj:      <HintPath>..\packages\NLog.2.1.0\lib\net45\NLog.dll</HintPath>
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Exception("Could not transform image", exception);
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Warn("Url for cloudinary id was null");
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Warn("Could not locate file object for cloudinary id in EpiServer");
 ....
 etc

当然,它找到了我要查找的内容,但我想过滤到仅以 .cs 结尾的文件。所以我尝试这样做:

git grep NLog **/*.cs
Web/Global.asax.cs:            NLogger.Info("Meny application start");

只有一击,我上面的两场比赛都没有列出。我发现这很奇怪,我可能误解了 git grep 的 globbing 匹配。有人可以启发我吗?

【问题讨论】:

  • git grep '*.cs' 是否按预期工作?
  • 尝试git grep '**/*.cs'(单引号或双引号),假设您使用的是各种标准外壳中的任何一种。可能您的外壳将 **/*.cs 扩展为 Web/Global.asax.cs 或类似的。请注意,只有 一些 shell 模拟 Git 的 **。 (当然,如果您也愿意在顶级目录中查找文件,只需 git grep '*.cs' 即可。)
  • @torek 就是这样。显然,这对我来说太晚了。请添加您的评论作为答案,我会给您答案。

标签: git grep glob


【解决方案1】:

(术语说明,对于阅读此答案的任何人:扩展诸如 *.cs 之类的内容称为“globbing”,1*.cs 是“shell glob”。“shell”是您的命令行解释器,可以是shbashzshdashtcsh等等。Git 会自带内置的globbing。扩展后的字符称为通配符,它们包括*?[。一些shell还特别对待{,这是使用Git的reflog名称时的问题,例如master@{yesterday}stash@{2}。报价始终适用于所有这些。)

在这种特殊情况下的问题——它可能会也可能不会发生在其他人身上,这取决于他们使用的 shell 和他们的环境——是一个未受保护(未引用)的* 经历了 shell globbing。一些 shell,比如 bash,会或者至少可以像 Git 一样扩展**,意思是“递归到子目录”。其他人不能,或者根据设置,不会。2

如果你的 shell 扩展 **/*.cs 以包含名称 Web/Global.asax.cs 但不包含 GETA.Seo.Sitemap/Services/CloudinaryService.cs (因为它在目录的下一层),那么当 Git 获取名称时,为时已晚:通配符* 字符消失了。 Git 永远不会看到它们,也无法进行自己的 globbing。

简单的解决方案是通过引用它们来保护通配符免受 shell globbing:

git grep '**/*.cs'

(成对的双引号——如git grep "**/*.cs"——也适用于大多数shell,前缀反斜杠在使用而不是引号时也适用,如git grep \*\*/\*.cs:只需用反斜杠保护每个易受攻击的字符)。对于许多 Git 命令——git grep 没有那么重要,除非你正在 grepping 较旧的提交——最好始终保护所有通配符,以便它们传递给 Git,因为 Git 会扩展它们 针对当前工作树以外的其他内容。 shell 只看到工作树。3)

虽然它依赖于 shell,但有时通配符会匹配 nothing 然后被传递。例如,如果您没有名为 sub 的目录并且您编写 sub/*,则某些(不是全部)shell 会将文字文本 sub/* 传递给您运行的命令。4 在这种情况下,如果该命令是一个 Git 命令,它可以再次进行自己的 globbing。依赖这一点是不明智的,因为一旦有 东西要匹配,shell 就会进行匹配,而不是将原始通配符传递给程序。


1名称“glob”是“global”的缩写,在早期的 shell 中,是由名为 glob 的外部程序完成的。 Early versions of Unix ran on machines with as little as 64 kilobytes of memory,因此没有太多空间进行花哨的壳内扩展。请参阅https://en.wikipedia.org/wiki/Glob_(programming) 了解更多信息。

2在bash中,Git风格的扩展是通过设置变量globstar来控制的。

3这甚至可能包括.git 存储库子目录本身,这通常很糟糕。在 bash 中,这是由变量 dotglob 控制的。

4在 bash 中,这是由 failglob 控制的。

请注意,bash 提供了几乎所有可能的 shell 的所有可能行为。它试图成为一种通用外壳。当然,这意味着它也需要所有这些控制变量,这使得 bash 变得非常庞大。您永远无法在 64K 非拆分 I&D PDP-11 上运行它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    相关资源
    最近更新 更多