Desejo fornecer um arquivo de configuração estruturado que seja o mais fácil possível para um usuário não técnico editar (infelizmente deve ser um arquivo) e, portanto, desejei usar o YAML. No entanto, não consigo encontrar nenhuma maneira de analisar isso em um script de shell Unix.
192
yq
para ler / gravar arquivos yaml no shell. A página do projeto está aqui: mikefarah.github.io/yq Você pode instalar a ferramenta combrew
,apt
ou fazer o download do binário. Ler um valor é tão simples quantoyq r some.yaml key.value
Respostas:
Meu caso de uso pode ou não ser exatamente o que esta postagem original estava perguntando, mas é definitivamente semelhante.
Eu preciso puxar alguns YAML como variáveis bash. O YAML nunca terá mais de um nível de profundidade.
YAML é assim:
Saída como um dis:
Eu consegui a saída com esta linha:
s/:[^:\/\/]/="/g
localiza:
e o substitui por="
, enquanto ignora://
(para URLs)s/$/"/g
anexa"
ao final de cada linhas/ *=/=/g
remove todos os espaços antes=
fonte
{KEY: 'value', ...}
; e possivelmente outros. Mais importante, se você pretende avaliar o resultado como código de shell, isso seria muito inseguro.Aqui está um analisador bash-only que aproveita o sed e o awk para analisar arquivos yaml simples:
Ele entende arquivos como:
Que, quando analisado usando:
irá produzir:
ele também entende arquivos yaml, gerados por ruby, que podem incluir símbolos ruby, como:
e produzirá o mesmo que no exemplo anterior.
O uso típico em um script é:
parse_yaml aceita um argumento de prefixo para que todas as configurações importadas tenham um prefixo comum (o que reduzirá o risco de colisões de namespace).
rendimentos:
Observe que as configurações anteriores em um arquivo podem ser referidas por configurações posteriores:
Outro uso interessante é primeiro analisar um arquivo padrão e, em seguida, as configurações do usuário, que funcionam, pois as últimas configurações substituem as primeiras:
fonte
-
notação yaml em matrizes nativas do bash!global__debug
vez deglobal_debug
.eu escrevi
shyaml
em python para necessidades de consulta YAML na linha de comando do shell.Visão geral:
Arquivo YAML do exemplo (com recursos complexos):
Consulta básica:
Consulta em loop mais complexa em valores complexos:
Alguns pontos-chave:
\0
saída acolchoada está disponível para manipulação sólida de múltiplas linhas.subvalue.maintainer
é uma chave válida).subvalue.things.-1
é o último elemento dasubvalue.things
sequência).Mais amostras e documentação estão disponíveis na página shyaml github ou na página shyaml PyPI .
fonte
cat docker-compose.yml | shyaml get-value api.environment | grep -v null | awk -F': ' '{print $2 > ("envdir/" $1)}'
shyaml
é ridiculamente lento( https://github.com/mikefarah/yq#readme )
Como exemplo (roubado diretamente da documentação ), dado um arquivo sample.yaml de:
então
irá produzir
fonte
É possível passar um pequeno script para alguns intérpretes, como Python. Uma maneira fácil de fazer isso usando Ruby e sua biblioteca YAML é o seguinte:
, onde
data
é um hash (ou matriz) com os valores de yaml.Como um bônus, ele analisará a matéria da frente de Jekyll muito bem.
fonte
RUBY_SCRIPT
variável é um script ruby que pode ser gravado em um arquivo (executado comruby -ryaml <rubyscript_filename>
). Ele contém a lógica para transformar o texto de entrada em algum texto de saída, armazenando internamente o conteúdo nadata
variável. O eco gera um texto yaml, mas você pode usarcat <yaml_filename>
para canalizar o conteúdo de um arquivo.stdout
alimentar a variável, não precisará confiar em arquivos temporários! usex=$(...)
ou mesmoread a b c < <(...)
). Portanto, essa é uma solução válida quando você sabe exatamente o que deseja buscar no arquivo YAML e sabe como escrever as linhas ruby para acessar esses dados. Mesmo que seja difícil, é uma prova completa do conceito da ideia IMHO. É verdade, no entanto, que ele não fornece uma abstração completa do bash.Dado que Python3 e PyYAML são dependências bastante fáceis de serem encontradas hoje em dia, o seguinte pode ajudar:
fonte
yaml.safe_load
como é mais seguro. pyyaml.org/wiki/PyYAMLDocumentationaqui uma versão estendida da resposta de Stefan Farestam:
Esta versão suporta o
-
notação e a notação curta de dicionários e listas. A seguinte entrada:produz esta saída:
como você pode ver o
-
itens são numerados automaticamente para obter nomes de variáveis diferentes para cada item. Nobash
não existem matrizes multidimensionais, essa é uma maneira de contornar. Vários níveis são suportados. Para contornar o problema de espaços em branco à direita mencionados por @briceburg, deve-se colocar os valores entre aspas simples ou duplas. No entanto, ainda existem algumas limitações: A expansão dos dicionários e listas pode produzir resultados incorretos quando os valores contêm vírgulas. Além disso, estruturas mais complexas, como valores que abrangem várias linhas (como ssh-keys), ainda não são suportadas.Algumas palavras sobre o código: O primeiro
sed
comando expande a forma abreviada de dicionários{ key: value, ...}
para regular e os converte para um estilo yaml mais simples. A segundased
chamada faz o mesmo para a notação curta de listas e é convertida[ entry, ... ]
em uma lista detalhada com a-
notação. A terceirased
chamada é a original que lidava com dicionários normais, agora com a adição de lidar com listas-
e recuos. Aawk
parte introduz um índice para cada nível de indentação e aumenta quando o nome da variável está vazio (ou seja, ao processar uma lista). O valor atual dos contadores é usado em vez do vname vazio. Ao subir um nível, os contadores são zerados.Edit: Eu criei um repositório do github para isso.
fonte
Difícil dizer porque depende do que você deseja que o analisador extraia do seu documento YAML. Para casos simples, que você pode ser capaz de usar
grep
,cut
,awk
etc. Para a análise mais complexa que você precisaria usar um full-blown analisar biblioteca, como Python PyYAML ou YAML :: Perl .fonte
Acabei de escrever um analisador que chamei Yay! ( Yaml não é Yamlesque! ), Que analisa Yamlesque , um pequeno subconjunto de YAML. Portanto, se você está procurando um analisador YAML 100% compatível com o Bash, não é isso. No entanto, para citar o OP, se você deseja um arquivo de configuração estruturado que seja o mais fácil possível para um usuário não técnico editar semelhante ao YAML, isso pode ser interessante.
Ele é inspirado pela resposta anterior, mas grava matrizes associativas ( sim, requer o Bash 4.x ) em vez de variáveis básicas. Isso é feito de uma maneira que permite que os dados sejam analisados sem o conhecimento prévio das chaves, para que o código controlado por dados possa ser gravado.
Assim como os elementos da matriz chave / valor, cada matriz possui uma
keys
matriz que contém uma lista de nomes de chaves, umachildren
matriz que contém nomes de matrizes filho e umaparent
chave que se refere ao seu pai.Este é um exemplo de Yamlesque:
Aqui está um exemplo mostrando como usá-lo:
quais saídas:
E aqui está o analisador:
Há alguma documentação no arquivo de origem vinculado e abaixo está uma breve explicação do que o código faz.
A
yay_parse
função primeiro localiza oinput
arquivo ou sai com um status de saída igual a 1. Em seguida, determina o conjunto de dadosprefix
, especificado explicitamente ou derivado do nome do arquivo.Ele grava
bash
comandos válidos em sua saída padrão que, se executados, definem matrizes que representam o conteúdo do arquivo de dados de entrada. O primeiro deles define a matriz de nível superior:Observe que as declarações de matriz são associativas (
-A
), que é um recurso da versão 4. do Bash. As declarações também são globais (-g
) para que possam ser executadas em uma função, mas estejam disponíveis para o escopo global como oyay
auxiliar:Os dados de entrada são processados inicialmente com
sed
. Ele descarta linhas que não correspondem à especificação do formato Yamlesque antes de delimitar os campos válidos do Yamlesque com um caractere ASCII File Separator e remover aspas duplas ao redor do campo de valor.As duas expressões são semelhantes; eles diferem apenas porque o primeiro seleciona valores entre aspas, enquanto que o segundo escolhe valores não citados.
O Separador de Arquivos (28 / hex 12 / octal 034) é usado porque, como um caractere não imprimível, é improvável que esteja nos dados de entrada.
O resultado é canalizado para o
awk
qual processa sua entrada uma linha por vez. Ele usa o caractere FS para atribuir cada campo a uma variável:Todas as linhas têm um recuo (possivelmente zero) e uma chave, mas nem todas têm um valor. Ele calcula um nível de recuo para a linha que divide o comprimento do primeiro campo, que contém o espaço em branco à esquerda, por dois. Os itens de nível superior sem nenhum recuo estão no nível de recuo zero.
Em seguida, ele decide o que
prefix
usar para o item atual. É isso que é adicionado a um nome de chave para criar um nome de matriz. Existe umroot_prefix
para a matriz de nível superior, definida como o nome do conjunto de dados e um sublinhado:A
parent_key
é a chave no nível de indentação acima do nível de indentação da linha atual e representa a coleção da qual a linha atual faz parte. Os pares chave / valor da coleção serão armazenados em uma matriz com seu nome definido como a concatenação deprefix
eparent_key
.Para o nível superior (nível de recuo zero), o prefixo do conjunto de dados é usado como chave pai, portanto, ele não possui prefixo (está definido como
""
). Todas as outras matrizes são prefixadas com o prefixo raiz.Em seguida, a chave atual é inserida em um array (interno do awk) contendo as chaves. Essa matriz persiste durante toda a sessão do awk e, portanto, contém chaves inseridas por linhas anteriores. A chave é inserida na matriz usando seu recuo como índice da matriz.
Como essa matriz contém chaves de linhas anteriores, quaisquer chaves com um ralador de nível de recuo além do nível de recuo da linha atual são removidas:
Isso deixa a matriz de chaves que contém o conjunto de chaves da raiz no nível de recuo 0 até a linha atual. Ele remove chaves obsoletas que permanecem quando a linha anterior foi recuada mais profundamente que a linha atual.
A seção final gera os
bash
comandos: uma linha de entrada sem valor inicia um novo nível de recuo (uma coleção na linguagem YAML) e uma linha de entrada com um valor adiciona uma chave à coleção atual.O nome da coleção é a concatenação da linha atual
prefix
eparent_key
.Quando uma chave tem um valor, uma chave com esse valor é atribuída à coleção atual como esta:
A primeira instrução gera o comando para atribuir o valor a um elemento de matriz associativa nomeado após a chave e a segunda gera o comando para adicionar a chave à
keys
lista delimitada por espaço da coleção :Quando uma chave não tem um valor, uma nova coleção é iniciada assim:
A primeira instrução gera o comando para adicionar a nova coleção à
children
lista delimitada por espaço da coleção atual e a segunda gera o comando para declarar uma nova matriz associativa para a nova coleção:Toda a saída de
yay_parse
pode ser analisada como comandos bash pelos comandos basheval
ousource
internos.fonte
examples
eusr/lib
, Estes estão ligados na minha resposta à pergunta. Se houver interesse, eu poderia dividi-lo em seu próprio repositório.fonte
Outra opção é converter o YAML em JSON e, em seguida, use jq para interagir com a representação JSON para extrair informações ou editá-las.
Eu escrevi um script simples do bash que contém essa cola - veja o projeto Y2J no GitHub
fonte
Se você precisar de um único valor, poderá usar uma ferramenta que converta seu documento YAML em JSON e alimente
jq
, por exemployq
.Conteúdo de sample.yaml:
Exemplo:
fonte
Sei que isso é muito específico, mas acho que minha resposta pode ser útil para determinados usuários.
Se você possui
node
enpm
instalou em sua máquina, você pode usá-lojs-yaml
.Primeira instalação:
então no seu script bash
Além disso, se você estiver usando,
jq
poderá fazer algo assimPorque
js-yaml
converte um arquivo yaml em um literal json string. Você pode usar a string com qualquer analisador json no seu sistema unix.fonte
Se você tem python 2 e PyYAML, pode usar este analisador que escrevi chamado parse_yaml.py . Algumas das coisas mais simples que faz é permitir que você escolha um prefixo (caso tenha mais de um arquivo com variáveis semelhantes) e escolha um único valor em um arquivo yaml.
Por exemplo, se você possui esses arquivos yaml:
staging.yaml:
prod.yaml:
Você pode carregar os dois sem conflito.
E até a cereja escolhe os valores que você deseja.
fonte
Você pode usar um equivalente de yq que está escrito em golang:
retorna:
fonte
Você também pode considerar o uso do Grunt (o JavaScript Task Runner). Pode ser facilmente integrado ao shell. Ele suporta a leitura de arquivos YAML (
grunt.file.readYAML
) e JSON (grunt.file.readJSON
).Isso pode ser conseguido através da criação de uma tarefa em
Gruntfile.js
(ouGruntfile.coffee
), por exemplo:depois, a partir do shell, basta executar
grunt foo
(verifiquegrunt --help
as tarefas disponíveis).Além disso, você pode implementar
exec:foo
task (grunt-exec
) com variáveis de entrada passadas de sua task (foo: { cmd: 'echo bar <%= foo %>' }
) para imprimir a saída no formato que desejar, e canalizá-la para outro comando.Também existe uma ferramenta semelhante ao Grunt, chamada gulp com o plug - in adicional gulp-yaml .
Instalar via:
npm install --save-dev gulp-yaml
Uso da amostra:
Para obter mais opções para lidar com o formato YAML , consulte o site do YAML em busca de projetos, bibliotecas e outros recursos disponíveis, que podem ajudá-lo a analisar esse formato.
Outras ferramentas:
Jshon
fonte
Sei que minha resposta é específica, mas se alguém já possui o PHP e o Symfony instalados, pode ser muito útil usar o analisador YAML do Symfony.
Por exemplo:
Aqui eu simplesmente utilizava
var_dump
a saída do array analisado, mas é claro que você pode fazer muito mais ... :)fonte