Estou tentando identificar quais arquivos no meu projeto têm cabeçalhos incorretos. Todos os arquivos começam assim
---
header:
.
.
.
title:
some header:
.
.
.
more headers:
level:
.
.
.
---
Onde . . . representa apenas mais cabeçalhos. Os cabeçalhos não contém recuo. Usando a seguinte expressão, consegui extrair o cabeçalho YAML de todos os arquivos.
grep -Przo --include=\*.md "^---(.|\n)*?---" .
Agora quero listar os cabeçalhos YAML incorretos.
- Cada cabeçalho YAML deve ter um
title: some text
- Todo cabeçalho YAML deve ter
language: [a-z]{2}
- Deve conter um
external: .*
ouauthor: .*
. - A colocação de
title:
,level:
,external:
elanguage:
varia.
Eu tentei fazer algo como
grep -L --include=\*.md -e "external: .*" -e "author: .* ."
No entanto, o problema com isso é que ele pesquisa o arquivo inteiro, não apenas o cabeçalho YAML. Então, acho que resolver os problemas acima se resume a como posso alimentar o resultado do cabeçalho YAML da minha pesquisa anterior no grep novamente. eu tentei
grep -Przo --include=\*.md "^---(.|\n)*?---" . | xargs -0 grep "title:";
No entanto, isso me deu um erro "Nenhum arquivo ou diretório", então estou um pouco incerto sobre como proceder.
Exemplos:
---
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
---
Correto YAML, tem autor, idioma e título.
---
title: Mini Golf
level: 2
language: en
external: http://appinventor.mit.edu/explore/ai2/minigolf.html
---
YAML correto, tem título, idioma e externo em vez de autor.
---
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
---
Cabeçalho YAML incorreto, autor ausente.
Aqui está uma maneira de fazer isso. Suponho que você tenha bash (para percorrer recursivamente os arquivos), sed e awk. Em vez de usar o bash, você pode usar
find
como alternativa-exec
para procurar os arquivos.O fluxo geral é:
*.md
arquivos, recursivamentesed
para extrair o cabeçalho YAMLO roteiro:
Você pode facilmente ajustar os padrões de correspondência regex no script awk para serem mais rígidos ou mais flexíveis, dependendo de seus requisitos exatos (talvez você queira caracteres alfanuméricos em vez de "qualquer", como o atual
.
em seu exemplo).A
sed
instrução extrai o cabeçalho YAML por:-n
)---
, fim de linha; o segundo padrão deve ocorrer após o primeiro padrão.p
gravadoO
awk
roteiro é um pouco exagerado, mas eu queria soletrá-lo para maior clareza. Cada vez que o awk é chamado, ele define três variáveis de flag para zero ou false. Se virmos linhas que correspondem aos nossos critérios, definimos o sinalizador correspondente como um/verdadeiro. Depois que todas as linhas forem vistas, retornamos sucesso ou falha com base no status desses sinalizadores - todos eles devem ser verdadeiros para "passar" na validação.Com esses arquivos de amostra com nomes apropriados espalhados no diretório atual e em um subdiretório:
... as saídas do script:
Para extrair o cabeçalho de um arquivo, podemos usar
sed
assim:Isso remove tudo do arquivo, exceto as linhas entre a linha 1 e a próxima linha que é exatamente
---
. A segunda expressão também exclui todas as---
linhas dos dados para que você fique apenas com o cabeçalho YAML.yq
Usarei o utilitário baseado em Python de Andrey Kislyuk . Como este é um wrapper útil em torno do versátil analisador JSONjq
, podemos detectar facilmente se os valores correspondentes às chaves sãonull
, non-null
ou uma string específica etc.Na
jq
sintaxe, podemos testar se uma chave,keyname
, existe em um objeto comhas("keyname")
. Também podemos testar se o valor de uma chave corresponde a uma expressão regular específica,RE
, usando.keyname | test("RE")
.Os testes mencionados na pergunta podem ser traduzidos na seguinte
jq
expressão:ou, mais curto, mas menos expressivo,
Isso garante que cada chave exista e que os valores para as chaves que precisam ter
null
valores diferentes estejam corretos.Executando isso nos três arquivos de exemplo, com nossos testes no arquivo de script
validate
:Podemos generalizar isso para testar todos os
.md
arquivos no diretório atual ou abaixo usandofind
assim:ou, com qualquer shell que suporte o
**
padrão globbing (habilitado comshopt -s globstar
inbash
):Aqui, também descartamos a saída
yq
e, em vez disso, usamos a ferramenta com sua-e
opção. Isso faz com que o status de saída do utilitário reflita o valor da última expressão avaliada, ou seja, zero para true e diferente de zero para false neste caso. Isso facilita o uso do nosso pipelinesed
+yq
diretamente em umaif
declaração.Executando isso com nossos três arquivos de teste, obtemos