Encontrando cabeçalhos YAML incorretos

2

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 expressão a seguir, consegui extrair o cabeçalho YAML de todos os arquivos.

grep -Przo --include=\*.md "^---(.|\n)*?---" .

Agora quero listar os cabeçalhos YAML incorretos.

  • Todo cabeçalho YAML deve ter title: some text
  • Todo cabeçalho YAML deve ter language: [a-z]{2}
  • Ele deve conter um external: .* ou author: .* .
  • O posicionamento de title: , level: , external: e language: varia.

Eu tentei fazer algo parecido com

grep -L --include=\*.md -e "external: .*" -e "author: .* ."

No entanto, o problema é que ele pesquisa o arquivo inteiro, não apenas o cabeçalho YAML. Então eu acho que resolver os problemas acima se resume a como eu 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", por isso 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
---

Corrigir YAML, tem um autor, idioma e título.

---
title: Mini Golf
level: 2
language: en
external: http://appinventor.mit.edu/explore/ai2/minigolf.html
---

Corrigir YAML, tem um 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.

    
por Øistein Søvik 19.07.2018 / 20:03

1 resposta

2

Aqui está uma maneira de fazer isso. Eu suponho que você tem bash (para loop recursivamente através dos arquivos), sed e awk. Em vez de usar o bash, você poderia alternativamente usar find com -exec para procurar pelos arquivos.

O fluxo geral é:

  1. pergunte ao bash pela lista de *.md arquivos, recursivamente
  2. passa cada arquivo para sed para extrair o cabeçalho YAML
  3. transmita esse cabeçalho YAML para awk para validação
  4. se o cabeçalho falhar na validação, imprima o nome do arquivo

O script:

#!/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

Você pode facilmente ajustar os padrões de correspondência regex no script awk para serem mais rígidos ou mais soltos, dependendo de suas necessidades exatas (talvez você queira caracteres alfanuméricos em vez de "any", como o atual . em seu exemplo possui).

A instrução sed extrai o cabeçalho YAML por:

  • suprimindo a impressão padrão ( -n )
  • pedindo uma linha de endereços que corresponda ao padrão: início da linha, --- , fim da linha; o segundo padrão deve ocorrer após o primeiro padrão.
  • esse intervalo de endereços é então p rinted

O script awk é um pouco over-built, mas eu queria soletrar para maior clareza. Cada vez que awk é chamado, ele define três variáveis de sinalização como zero ou falso. Se virmos linhas que correspondem aos nossos critérios, definimos o sinalizador correspondente como um / verdadeiro. Uma vez que todas as linhas tenham sido vistas, retornamos sucesso ou falha com base no status dessas flags - elas devem ser todas verdadeiras para "passar" a validação.

Com esses arquivos de amostra adequadamente nomeados espalhados no diretório atual e em um subdiretório:

$ tree .
.
├── bad1.md
├── good1.md
├── good2.md
└── subdir
    ├── bad1.md
    └── good1.md

1 directory, 5 files

... o script mostra:

Incorrect header found in bad1.md
Incorrect header found in subdir/bad1.md
    
por 20.07.2018 / 23:28

Tags