내 프로젝트의 어떤 파일에 잘못된 헤더가 있는지 확인하려고 합니다. 파일은 모두 다음과 같이 시작됩니다.
---
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
) - 다음 패턴과 일치하는 줄의 주소를 요청합니다. 줄 시작,
---
줄 끝 두 번째 패턴은 첫 번째 패턴 뒤에 나타나야 합니다. p
그런 다음 해당 주소 범위를 인쇄하십시오.
스크립트 awk
가 약간 과하게 구성되어 있지만 명확성을 위해 설명하겠습니다. awk가 호출될 때마다 세 개의 플래그 변수를 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과 다음 라인(일 경우) 사이를 제외하고 파일에서 모든 내용이 제거됩니다 ---
. 두 번째 표현식은 또한 ---
데이터의 모든 라인을 제거하므로 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
값이 아닌 값이 필요한 키의 값이 올바른지 확인됩니다.
세 개의 샘플 파일에 대해 이 명령을 실행하고 스크립트 파일에서 테스트합니다 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
옵션을 사용합니다. 이렇게 하면 유틸리티의 종료 상태가 마지막으로 평가된 표현식의 값인 0을 반영하게 됩니다.진짜, 그리고 0이 아닌잘못된이 경우. 이렇게 하면 명령문에서 sed
+ 파이프를 직접 사용하는 것이 yq
쉬워집니다 if
.
우리가 얻은 세 가지 테스트 파일을 사용하여 이를 실행합니다.
Invalid YAML header: ./file3.md