私のプロジェクトのどのファイルに間違ったヘッダーがあるかを確認しようとしています。ファイルはすべて次のように始まります。
---
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ヘッダー、著者の欠落。
答え1
これは一つの方法です。私はあなたがbash(再帰的にファイルを繰り返す)、sedとawkを持っていると仮定します。 bashを使用する代わりにfind
withを使用-exec
してファイルを検索することもできます。
一般的なプロセスは次のとおりです。
*.md
bashにファイルリストを再帰的に要求する- 各ファイルを渡して
sed
YAMLヘッダーを抽出する - 検証のために、このYAMLヘッダーをawkに渡してください。
- ヘッダーの検証に失敗した場合は、ファイル名を印刷します。
スクリプト:
#!/bin/bash
shopt -s globstar
for file in **/*.md
do
# use sed for the header
sed -n /^---$/,/^---$/p "$file" |
awk '
BEGIN {
good_title=0
good_lang=0
good_extaut=0
}
/^title: .*/ { good_title=1 }
/^language: [a-z][a-z]$/ { good_lang=1 }
/^author: .*/ { good_extaut=1 }
/^external: .*/ { good_extaut=1 }
END {
if (good_title && good_lang && good_extaut)
exit 0
else
exit 1
}
' \
|| printf "Incorrect header found in %s\n" "$file"
done
.
特定の要件に応じて、awkスクリプトの正規表現一致パターンをより厳密または緩やかに簡単に調整できます(例の現在の文字のように、「any」ではなく英数字が必要になる場合があります)。
このsed
ステートメントは、次のようにYAMLヘッダーを抽出します。
- デフォルト印刷を無効にする(
-n
) - 次のパターンに一致する行のアドレスを要求します。行の始まり、行の終わり
---
2番目のパターンは最初のパターンの後に表示する必要があります。 p
次に、対応するアドレス範囲を印刷します。
スクリプトawk
は少し過度に構成されていますが、明確にするために説明します。 awkが呼び出されるたびに、3つのフラグ変数を0またはfalseに設定します。基準を満たす行がある場合は、そのフラグを1 / trueに設定します。すべての行が確認されると、これらのフラグの状態に基づいて成功または失敗を返します。検証を「通過」するには、すべてtrueでなければなりません。
適切に名前が付けられたサンプルファイルを現在のディレクトリとサブディレクトリに分散します。
$ tree .
.
├── bad1.md
├── good1.md
├── good2.md
└── subdir
├── bad1.md
└── good1.md
1 directory, 5 files
...スクリプト出力:
Incorrect header found in bad1.md
Incorrect header found in subdir/bad1.md
答え2
ファイルヘッダーを抽出するには、sed
次のように使用できます。
sed -e '1,/^---$/!d' -e '/^---$/d' filename
これにより、行1と次の行(ある場合)の間を除き、ファイルからすべての内容が削除されます---
。 2番目の式は---
データのすべての行も削除するため、YAMLヘッダーのみが残ります。
yq
Pythonベースのユーティリティを使いましょう。アンドレイ・キースリューク。これは多目的JSONパーサーのための便利なラッパーなので、jq
キーに対応する値が特定の文字列かnull
どうかを簡単に検出できます。null
jq
構文では、キーがkeyname
オブジェクトに存在するかどうかをテストできますhas("keyname")
。RE
キー値が特定の正規表現と一致することをテストすることもできます.keyname | test("RE")
。
質問に記載されているテストは、次のjq
式に翻訳できます。
has("title") and
(.title | test(".")) and
has("language") and
(.language | test("[a-z]{2}")) and
(has("external") or has("author"))
または、より短いですが、あまり表現的ではありません。
(.title? != null) and
(.language? | test("[a-z]{2}")) and
(has("external") or has("author"))
これにより、すべてのキーが存在し、値null
以外の値を必要とするキーの値が正しいことが確認されます。
3つのサンプルファイルに対してこのコマンドを実行し、スクリプトファイルでテストしますvalidate
。
$ sed -e '1,/^---$/!d' -e '/^---$/d' file1.md | yq -f validate
true
$ sed -e '1,/^---$/!d' -e '/^---$/d' file2.md | yq -f validate
true
$ sed -e '1,/^---$/!d' -e '/^---$/d' file3.md | yq -f validate
false
.md
これを一般化して、現在のディレクトリまたはその下のディレクトリ内のすべてのファイルをテストできます。find
次のようになります。
find . -name '*.md' -type f -exec sh -c '
for pathname do
if ! sed -e "1,/^---\$/!d" -e "/^---\$/d" "$pathname" |
yq -e -f validate >/dev/null
then
printf "Invalid YAML header: %s\n" "$pathname"
fi
done' sh {} +
または、**
グローブモードをサポートするシェルを使用してください(shopt -s globstar
inで有効bash
)。
for pathname in ./**/*.md
do
if ! sed -e '1,/^---$/!d' -e '/^---$/d' "$pathname" |
yq -e -f validate >/dev/null
then
printf 'Invalid YAML header: %s\n' "$pathname"
fi
done
ここではさらに出力を削除し、yq
代わりにツールとその-e
オプションを使用します。これにより、ユーティリティの終了ステータスは、最後に評価された式の値であるゼロを反映します。本物、そしてゼロ以外間違ったこの場合。これにより、ステートメントでsed
+パイプを直接使用するのがyq
簡単になりますif
。
私たちが得た3つのテストファイルを使ってそれを実行します。
Invalid YAML header: ./file3.md