Deseo proporcionar un archivo de configuración estructurado que sea lo más fácil posible para que lo edite un usuario no técnico (desafortunadamente tiene que ser un archivo) y por eso quería usar YAML. Sin embargo, no puedo encontrar ninguna manera de analizar esto desde un script de shell de Unix.
192

yqpara leer / escribir archivos yaml en shell. La página del proyecto está aquí: mikefarah.github.io/yq Puede instalar la herramienta conbrew,apto descargar el binario. Leer un valor es tan simple comoyq r some.yaml key.valueRespuestas:
Mi caso de uso puede o no ser el mismo que el que estaba preguntando esta publicación original, pero definitivamente es similar.
Necesito obtener algunos YAML como variables bash. El YAML nunca tendrá más de un nivel de profundidad.
YAML se ve así:
Salida like-a dis:
Logré el resultado con esta línea:
s/:[^:\/\/]/="/glo encuentra:y lo reemplaza por=", mientras lo ignora://(para URL)s/$/"/gse agrega"al final de cada líneas/ *=/=/gelimina todos los espacios antes=fuente
{KEY: 'value', ...}; y posiblemente otros. Lo más importante, si tiene la intención de evaluar el resultado como código shell, sería muy inseguro.Aquí hay un analizador de solo bash que aprovecha sed y awk para analizar archivos yaml simples:
Entiende archivos como:
Que, cuando se analiza usando:
dará salida:
también comprende archivos yaml, generados por ruby que pueden incluir símbolos ruby, como:
y generará lo mismo que en el ejemplo anterior.
El uso típico dentro de un script es:
parse_yaml acepta un argumento de prefijo para que todas las configuraciones importadas tengan un prefijo común (lo que reducirá el riesgo de colisiones en el espacio de nombres).
rendimientos:
Tenga en cuenta que las configuraciones anteriores en un archivo pueden ser referidas por configuraciones posteriores:
Otro buen uso es analizar primero un archivo predeterminado y luego la configuración del usuario, que funciona ya que esta última anula la primera:
fuente
-notación yaml en matrices bash nativas también!global__debuglugar deglobal_debug.He escrito
shyamlen Python para las necesidades de consulta de YAML desde la línea de comandos del shell.Visión general:
Archivo YAML de ejemplo (con características complejas):
Consulta básica:
Consulta de bucle más compleja sobre valores complejos:
Algunos puntos clave:
\0La salida acolchada está disponible para la manipulación sólida de entradas multilínea.subvalue.maintaineres una clave válida).subvalue.things.-1es el último elemento de lasubvalue.thingssecuencia).Hay más muestras y documentación disponibles en la página de Github de shyaml o en la página de PyPI de shyaml .
fuente
cat docker-compose.yml | shyaml get-value api.environment | grep -v null | awk -F': ' '{print $2 > ("envdir/" $1)}'shyamles ridículamente lento( https://github.com/mikefarah/yq#readme )
Como ejemplo (robado directamente de la documentación ), dado un archivo sample.yaml de:
luego
saldrá
fuente
Es posible pasar un pequeño script a algunos intérpretes, como Python. Una manera fácil de hacerlo usando Ruby y su biblioteca YAML es la siguiente:
, donde
dataes un hash (o matriz) con los valores de yaml.Como beneficio adicional, analizará muy bien el frente de Jekyll .
fuente
RUBY_SCRIPTvariable es un script ruby que puede escribirse en un archivo en su lugar (ejecutarse conruby -ryaml <rubyscript_filename>). Contiene la lógica para transformar el texto de entrada en texto de salida, almacenando internamente el contenido en ladatavariable. El eco genera un texto yaml, pero puede utilizarlocat <yaml_filename>para canalizar el contenido de un archivo.stdoutque se alimente a la variable, no tienes que confiar en archivos temporales! usox=$(...)o inclusoread a b c < <(...)). Por lo tanto, esta es una solución válida cuando sabe exactamente lo que desea obtener en el archivo YAML y sabe cómo escribir las líneas rubí para acceder a estos datos. Incluso si es tosco, es una prueba completa del concepto de la idea en mi humilde opinión. Sin embargo, es cierto que no le proporciona una abstracción completa de bash.Dado que Python3 y PyYAML son dependencias bastante fáciles de cumplir hoy en día, lo siguiente puede ayudar:
fuente
yaml.safe_loadcomo es más seguro. pyyaml.org/wiki/PyYAMLDocumentationaquí una versión extendida de la respuesta de Stefan Farestam:
Esta versión admite la
-notación y la notación corta para diccionarios y listas. La siguiente entrada:produce esta salida:
como puede ver, los
-elementos se numeran automáticamente para obtener diferentes nombres de variables para cada elemento. Enbashno hay matrices multidimensionales, por lo que esta es una forma de trabajo alrededor. Múltiples niveles son compatibles. Para evitar el problema de los espacios en blanco finales mencionados por @briceburg, se deben encerrar los valores entre comillas simples o dobles. Sin embargo, todavía hay algunas limitaciones: la expansión de los diccionarios y las listas puede producir resultados incorrectos cuando los valores contienen comas. Además, las estructuras más complejas, como los valores que abarcan varias líneas (como las teclas ssh) no son compatibles (todavía).Algunas palabras sobre el código: el primer
sedcomando expande la forma abreviada de los diccionarios{ key: value, ...}a regular y los convierte a un estilo yaml más simple. La segundasedllamada hace lo mismo para la notación corta de listas y se convierte[ entry, ... ]en una lista detallada con la-notación. La tercerasedllamada es la original que maneja los diccionarios normales, ahora con la adición de manejar listas con-sangrías. Laawkparte introduce un índice para cada nivel de sangría y lo aumenta cuando el nombre de la variable está vacío (es decir, al procesar una lista). Se utiliza el valor actual de los contadores en lugar del nombre de v vacío. Al subir un nivel, los contadores se ponen a cero.Editar: he creado un repositorio github para esto.
fuente
Difícil de decir porque depende de lo que quiera que extraiga el analizador de su documento YAML. Para los casos simples, es posible que pueda utilizar
grep,cut,awketc. Para el análisis más complejo que tendría que utilizar un análisis en toda regla biblioteca de Python como PyYAML o YAML :: Perl .fuente
¡Acabo de escribir un analizador que llamé Yay! (¡ Yaml no es Yamlesque! ) Que analiza Yamlesque , un pequeño subconjunto de YAML. Entonces, si está buscando un analizador YAML 100% compatible para Bash, entonces este no lo es. Sin embargo, para citar el OP, si desea un archivo de configuración estructurado que sea lo más fácil posible para un usuario no técnico para editar que sea similar a YAML, esto puede ser de interés.
Está inspirado en la respuesta anterior, pero escribe matrices asociativas ( sí, requiere Bash 4.x ) en lugar de variables básicas. Lo hace de una manera que permite analizar los datos sin el conocimiento previo de las claves para que se pueda escribir el código controlado por datos.
Además de los elementos de la matriz de clave / valor, cada matriz tiene una
keysmatriz que contiene una lista de nombres de clave, unachildrenmatriz que contiene nombres de matrices secundarias y unaparentclave que se refiere a su padre.Este es un ejemplo de Yamlesque:
Aquí hay un ejemplo que muestra cómo usarlo:
que salidas:
Y aquí está el analizador:
Hay algo de documentación en el archivo fuente vinculado y a continuación hay una breve explicación de lo que hace el código.
La
yay_parsefunción primero localiza elinputarchivo o sale con un estado de salida de 1. Luego, determina el conjunto de datosprefix, ya sea explícitamente especificado o derivado del nombre del archivo.Escribe
bashcomandos válidos en su salida estándar que, si se ejecutan, definen matrices que representan el contenido del archivo de datos de entrada. El primero de ellos define la matriz de nivel superior:Tenga en cuenta que las declaraciones de matriz son asociativas (
-A), que es una característica de Bash versión 4. Las declaraciones también son globales (-g), por lo que pueden ejecutarse en una función pero estar disponibles para el alcance global como elyayayudante:Los datos de entrada se procesan inicialmente con
sed. Descarta líneas que no coinciden con la especificación de formato Yamlesque antes de delimitar los campos válidos de Yamlesque con un carácter de separador de archivo ASCII y eliminar las comillas dobles que rodean el campo de valor.Las dos expresiones son similares; difieren solo porque el primero selecciona los valores entre comillas, mientras que el segundo selecciona los que no están entre comillas.
El separador de archivos (28 / hex 12 / octal 034) se utiliza porque, como carácter no imprimible, es poco probable que esté en los datos de entrada.
El resultado se canaliza en el
awkque procesa su entrada una línea a la vez. Utiliza el FS caracteres para asignar cada campo a una variable:Todas las líneas tienen una sangría (posiblemente cero) y una clave, pero no todas tienen un valor. Calcula un nivel de sangría para la línea que divide la longitud del primer campo, que contiene el espacio en blanco inicial, por dos. Los elementos de nivel superior sin sangría están en el nivel de sangría cero.
A continuación, determina qué
prefixusar para el elemento actual. Esto es lo que se agrega al nombre de una clave para crear un nombre de matriz. Hay unaroot_prefixpara la matriz de nivel superior que se define como el nombre de conjunto de datos y un carácter de subrayado:La
parent_keyes la clave en el nivel de sangría por encima del nivel de sangría de la línea actual y representa la colección de la que forma parte la línea actual. Los pares clave / valor de la colección se almacenarán en una matriz con su nombre definido como la concatenación deprefixyparent_key.Para el nivel superior (nivel de sangría cero), el prefijo del conjunto de datos se utiliza como clave principal, por lo que no tiene prefijo (está establecido en
""). Todos los demás arreglos tienen el prefijo raíz.A continuación, la clave actual se inserta en una matriz (awk-internal) que contiene las claves. Esta matriz persiste durante toda la sesión awk y, por lo tanto, contiene claves insertadas por líneas anteriores. La clave se inserta en la matriz usando su sangría como índice de la matriz.
Debido a que esta matriz contiene claves de líneas anteriores, se eliminan todas las claves con un nivel de sangría mayor que el nivel de sangría de la línea actual:
Esto deja la matriz de claves que contiene el llavero desde la raíz en el nivel de sangría 0 a la línea actual. Elimina las claves obsoletas que permanecen cuando la línea anterior se sangra más profundo que la línea actual.
La sección final genera los
bashcomandos: una línea de entrada sin un valor inicia un nuevo nivel de sangría (una colección en lenguaje YAML) y una línea de entrada con un valor agrega una clave a la colección actual.El nombre de la colección es la concatenación de la línea actual
prefixyparent_key.Cuando una clave tiene un valor, una clave con ese valor se asigna a la colección actual de esta manera:
La primera instrucción genera el comando para asignar el valor a un elemento de matriz asociativo nombrado después de la clave y la segunda genera el comando para agregar la clave a la
keyslista delimitada por espacios de la colección :Cuando una clave no tiene un valor, se inicia una nueva colección como esta:
La primera instrucción genera el comando para agregar la nueva colección a la
childrenlista delimitada por espacios de la colección actual y la segunda genera el comando para declarar una nueva matriz asociativa para la nueva colección:Toda la salida de
yay_parsepuede ser analizada como comandos bash por los comandos bashevalosourceintegrados.fuente
examplesyusr/lib, Estos están vinculados en mi respuesta a la pregunta. Si hay interés, podría dividirlo en su propio repositorio.fuente
Otra opción es convertir el YAML a JSON, luego usar jq para interactuar con la representación JSON, ya sea para extraer información o editarla.
Escribí un script de bash simple que contiene este pegamento; vea el proyecto Y2J en GitHub
fuente
Si necesita un valor único, podría utilizar una herramienta que convierta su documento YAML a JSON y lo alimente
jq, por ejemployq.Contenido de sample.yaml:
Ejemplo:
fuente
Sé que esto es muy específico, pero creo que mi respuesta podría ser útil para ciertos usuarios.
Si tiene
nodeenpminstaló en su máquina, puede usarjs-yaml.Primera instalación:
entonces en tu script bash
Además, si estás usando
jqpuedes hacer algo asíPorque
js-yamlconvierte un archivo yaml en un literal de cadena json. Luego puede usar la cadena con cualquier analizador json en su sistema unix.fuente
Si tiene Python 2 y PyYAML, puede usar este analizador que escribí llamado parse_yaml.py . Algunas de las cosas más ingeniosas que hace es permitirle elegir un prefijo (en caso de que tenga más de un archivo con variables similares) y elegir un solo valor de un archivo yaml.
Por ejemplo, si tiene estos archivos yaml:
staging.yaml:
prod.yaml:
Puede cargar ambos sin conflicto.
E incluso elige los valores que quieras.
fuente
Podrías usar un equivalente de yq que está escrito en golang:
devoluciones:
fuente
También puede considerar usar Grunt (The JavaScript Task Runner). Se puede integrar fácilmente con la carcasa. Admite la lectura de archivos YAML (
grunt.file.readYAML) y JSON (grunt.file.readJSON).Esto se puede lograr creando una tarea en
Gruntfile.js(oGruntfile.coffee), por ejemplo:luego desde shell simplemente ejecute
grunt foo(verifiquegrunt --helplas tareas disponibles)Además, puede implementar
exec:footareas (grunt-exec) con variables de entrada pasadas desde su tarea (foo: { cmd: 'echo bar <%= foo %>' }) para imprimir la salida en el formato que desee y luego canalizarla a otro comando.También hay una herramienta similar a Grunt, se llama gulp con el complemento adicional gulp-yaml .
Instalar a través de:
npm install --save-dev gulp-yamlUso de la muestra:
Para obtener más opciones para lidiar con el formato YAML , consulte el sitio de YAML para ver los proyectos, bibliotecas y otros recursos disponibles que pueden ayudarlo a analizar ese formato.
Otras herramientas:
Jshon
fuente
Sé que mi respuesta es específica, pero si uno ya tiene PHP y Symfony instalados, puede ser muy útil usar el analizador YAML de Symfony.
Por ejemplo:
Aquí simplemente solía
var_dumpgenerar la matriz analizada pero, por supuesto, puedes hacer mucho más ... :)fuente