bash - 如何在此递归查找和替换中引用当前路径?
问题描述
免责声明:(离题警告)这不是关于输出在 repo 中实际检测到的被忽略文件的列表。这是关于被忽略的路径,即使实际上没有文件与这些路径之一匹配。
上下文:我正在尝试编写一个 git 别名以递归地“展平”所有 .gitignore 模式并输出从顶层看到的路径列表。
我的意思是举个例子:
├─ .git
├─ .gitignore
└─ dir1
├─ .gitignore
├─ file1.txt
└─ file2.txt
在.gitignore
文件中包含这些内容:
# (currently pointing at top-level directory)
$ cat .gitignore
some_path
$ cat dir1/.gitignore
yet_another_path
*.txt
我尝试有一个别名来输出一些类似的东西
$ git flattened-ignore-list
some_path
dir1/yet_another_path
dir1/*.txt
到目前为止我有什么?
我知道我可以在 repo 中搜索所有 .gitignore 文件
find . -name ".gitignore"
在这种情况下会输出
.gitignore
dir1/.gitignore
所以我试图将其与cat
获取它们的内容(这些工作中的任何一个)结合起来
find . -name ".gitignore" | xargs cat
# or
cat $(find . -name ".gitignore")
结果:
some_path
yet_another_path
*.txt
这在技术上是预期的,但不幸的是对我想要实现的目标没有帮助。所以(终于!)到达我的实际问题:
对于 的每个结果,我如何find
参考当前路径?(为了最终将其添加到行中)
怀疑 XY 问题的人的注意事项:可能是这种情况,我的方法在这里可能只是幼稚,但也许不是,我不确定。例如,我没有考虑嵌套 .gitignore 文件可以引用上层文件或带有 .gitignore 的特殊语法的复杂情况**
。我现在坚持非常简单的结构,所以如果你发现一个缺陷和/或可以提出完全不同的方法来实现相同的目标,我当然也会很高兴听到它。
解决方案
我尝试有一个别名来输出一些类似的东西
$ git flattened-ignore-list some_path dir1/yet_another_path dir1/*.txt
不幸的是,这种方法是幼稚的(也许注定要失败,但也许不是),因为.gitignore
文件中的条目有点复杂。
您提出的简单问题的简单答案是使用相对于顶级目录名称的前缀。由于find
从不输出不必要的复杂名称,您可以通过直接字符串处理来做到这一点:
.gitignore dir1/.gitignore
dir1
告诉您,在读取第一个文件时,不要添加任何内容,而在读取第二个文件时,请添加到每个条目的前面。在 shell 中执行此操作有点棘手,但 bash 有所需的工具:您只需将行减去/.gitignore
末尾的行,使用正则表达式替换或仅从任何有斜杠的内容中删除 11 个字符(如果我数正确的话)或者不是文字 10-character string .gitignore
。将目录从/.gitignore
名称之前的部分中取出并使用sed
或awk
插入它,并在非注释条目前面加上斜线(并记住处理!
条目略有不同)。
你可能最好单独处理顶层.gitignore
——你可以直接复制它,必要时添加一个最后的换行符——然后.gitignore
在不同的代码路径中处理子目录。
请注意,子目录.gitignore
不能引用它上面的东西:无论是否被忽略,dir1/.gitignore
都无法改变。所以那部分不是问题。./foo
dir2/foo
有问题的部分是,在dir1
,条目:
*.txt
意味着顶层不仅应该忽略未跟踪的dir1/*.txt
文件,还应该忽略dir1/sub/*.txt
文件,dir1/sub/sub2/*.txt
等等。然而,一个dir1
条目阅读:
sub/*.txt
意味着顶层应该只忽略未跟踪的dir1/sub/*.txt
文件,而不忽略任何dir1/sub/sub2/*.txt
文件!
您也许可以使用更多代码来挽救这一点:在读取子目录.gitignore
时,检查任何给定行中是否有嵌入的斜杠。嵌入的斜线不是最终的斜线,因为最终的斜线被删除以用于这种特殊的区分。
如果条目包含嵌入的斜杠,则它仅适用于完整路径相对于子目录。因此,您可以
dir1/
在前面添加并完成,例如:dir1/foo/*.txt
如果条目不包含嵌入的斜杠,则它适用于子目录及其所有嵌套的子子目录。您将需要允许任意数量的子目录。这可能是正确的,但它未经测试:
dir1/*.txt dir1/**/*.txt
(理论上也应该
**/
匹配子目录的空列表,因此只需要第二行,但实际上我发现在某些情况下不会发生这种情况。我不记得这是在其他路径规范、文件还是两者中。 ).gitignore
通常,大多数.gitignore
条目似乎不包含嵌入的斜杠,因此与输入长度相比,您编写的任何成功的脚本都可能会产生一个几乎双倍长度的“扁平”忽略文件。