我正在尝试确定我的项目中哪些文件的标头不正确。文件都是这样开始的
---
header:
.
.
.
title:
some header:
.
.
.
more headers:
level:
.
.
.
---
在哪里 。. . 只代表更多的标题。标题不包含缩进。使用以下表达式,我已经能够从每个文件中提取 YAML 标头。
grep -Przo --include=\*.md "^---(.|\n)*?---" .
现在我想列出不正确的 YAML 标头。
- 每个 YAML 标头都必须有一个
title: some text
- 每个 YAML 标头都必须有
language: [a-z]{2}
- 它必须包含一个
external: .*
或author: .*
。 title:
、level:
和external:
的位置language:
各不相同。
我试着做类似的事情
grep -L --include=\*.md -e "external: .*" -e "author: .* ."
然而,这样做的问题是它会搜索整个文件,而不仅仅是 YAML 标头。所以我想解决上述问题归结为如何将我之前搜索的 YAML 标头结果再次输入 grep。我试过了
grep -Przo --include=\*.md "^---(.|\n)*?---" . | xargs -0 grep "title:";
然而,这给了我一个错误“没有这样的文件或目录”,所以我有点不确定如何继续。
例子:
---
title: Rull-en-ball
level: 1
author: Transkribert og oversatt fra [Unity3D](http://unity3d.com)
translator: Bjørn Fjukstad
license: Oversatt fra [unity3d.com](https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial)
language: nb
---
正确的 YAML,有作者、语言和标题。
---
title: Mini Golf
level: 2
language: en
external: http://appinventor.mit.edu/explore/ai2/minigolf.html
---
正确的 YAML,有标题、语言和外部而不是作者。
---
title: 'Stjerner og galakser'
level: 2
logo: ../../assets/img/ccuk_logo.png
license: '[Code Club World Limited Terms of Service](https://github.com/CodeClub/scratch-curriculum/blob/master/LICENSE.md)'
translator: 'Ole Andreas Ramsdal'
language: nb
---
YAML 标头不正确,缺少作者。
这是一种方法。我假设您有 bash(通过文件递归循环)、sed 和 awk。除了使用 bash,您还可以使用
find
with-exec
来搜索文件。一般流程是:
*.md
递归地向 bash 询问文件列表sed
给以提取 YAML 标头剧本:
您可以轻松地将 awk 脚本中的正则表达式匹配模式调整为更严格或更宽松,具体取决于您的具体要求(也许您想要字母数字字符而不是“任何”,如
.
示例中的当前字符)。该
sed
语句通过以下方式提取 YAML 标头:-n
)---
行尾;第二个模式必须出现在第一个模式之后。p
然后打印该地址范围该
awk
脚本有点过度构建,但为了清楚起见,我想将其拼写出来。每次调用 awk 时,它都会将三个标志变量设置为零或假。如果我们看到符合我们标准的行,我们将相应的标志设置为 one/true。一旦看到所有行,我们将根据这些标志的状态返回成功或失败——它们必须全部为真才能“通过”验证。将这些适当命名的示例文件分散到当前目录和一个子目录中:
...脚本输出:
要提取文件的标题,我们可以
sed
这样使用:这将删除文件中的所有内容,除了第 1 行和下一行之间的行
---
。第二个表达式还删除---
了数据中的所有行,这样您就只剩下 YAML 标头了。我将使用来自 Andrey Kislyuk
yq
的基于 Python 的实用程序。由于这是对多功能 JSON 解析器的方便包装,我们可以轻松检测对应于键的值是、非还是特定字符串等。jq
null
null
在
jq
语法中,我们可以测试一个键,keyname
,是否存在于一个带有 的对象中has("keyname")
。我们还可以使用 测试键的值是否与特定的正则表达式RE
匹配.keyname | test("RE")
。问题中提到的测试可以翻译成以下
jq
表达式:或者,更短但表现力较低,
这确保每个键都存在,并且需要具有非
null
值的键的值是正确的。在三个示例文件上运行它,我们的测试在脚本文件中
validate
:我们可以将其概括为测试
.md
当前目录或以下目录中的所有文件,如下所示find
:或者,使用任何支持通配模式的 shell (使用in
**
启用):shopt -s globstar
bash
在这里,我们还丢弃了输出
yq
,而是使用该工具及其-e
选项。这使得实用程序的退出状态反映了最后计算的表达式的值,即在这种情况下,零表示true,非零表示false 。这使得直接在语句中使用我们的sed
+管道变得容易。yq
if
使用我们的三个测试文件运行它,我们得到