¿Puedo convertir directamente un archivo que enumera varias variables a JSON usando la línea de comando?

¿Puedo convertir directamente un archivo que enumera varias variables a JSON usando la línea de comando?

Digamos que tengo un filecon el siguiente contenido:

var1='a random text'
var2='another random text'
var3='a third random text'

Sé que si uso el comando evalcomo el siguiente almacenaré todas esas variables directamente en mi shell:

$ eval $(cat file)

Al hacer eso, mi shell creará archivos $var1, $var2y $var3con sus respectivos contenidos. Sabiendo eso, podría generar un JSON manualmente como el siguiente:

$ JSON="{ \"var1\" : \"$var1\", \"var2\" : \"$var2\", \"var3\" : \"$var3\"}"

Y eso daría como resultado un JSON válido:

$ echo $JSON
{ "var1" : "a random text", "var2" : "another random text", "var3" : "a third random text"}

El problema aquí es que estoy codificando las claves var1, var2 y var3... En mi caso, el archivo podría ser más grande y con más variables almacenadas (no solo var1, var2 y var3). Estaba pensando si hay una manera fácil de lograrlo usando la línea de comando, tal como evallo hace para almacenar variables de archivos en el Shell, pero en lugar de almacenar las variables, generando una salida JSON. ¿Es posible? ¿Puedo convertir directamente un archivo estructurado así a JSON usando la línea de comando?


Mi solución alternativa aquí sería desarrollar un código (sin usar Shell) que vaya carácter por carácter dentro de este archivo y luego separe todo dinámicamente en un bucle. Pero hago esta pregunta porque quiero evitar complicar demasiado la solución.

Respuesta1

Usando una combinación de jo(deaquí) y jqdeaquí), sin crear variables de shell ni permitir que el shell interprete el archivo en absoluto:

jo <file |
jq --arg sq "'" '.[] |= ( ltrimstr($sq) | rtrimstr($sq) )'

Esto primero se utiliza jopara crear el documento JSON.

{
   "var1": "'a random text'",
   "var2": "'another random text'",
   "var3": "'a third random text'"
}

(pero en una sola línea). Para ello, interpreta las asignaciones de variables en su archivo como pares clave-valor.

Luego, la jqherramienta se utiliza para eliminar las comillas simples del inicio y el final de cada valor.

El resultado final es

{
  "var1": "a random text",
  "var2": "another random text",
  "var3": "a third random text"
}

Esto no solucionará las nuevas líneas incrustadas en los valores. Sin embargo, otros caracteres especiales se codificarán automáticamente en JSON mediante jo.

Respuesta2

Con zsh, y asumiendo que el archivo tiene una sintaxis compatible con la de zsh, que el archivo no utiliza funciones de expansión de shell (como var1=~/foo, var2=$var1, var3=$(uname)...) y que los valores son texto codificado en UTF-8, podría hacerlo :

tokens=( ${(Q)${(zZ[nC])"$(<file)"}} )

Para tokenizar el contenido de ese archivo según la sintaxis del shell (usando el zindicador de expansión de parámetros, modificado (con Z[flags]) con npara considerar líneas nuevas sin comillas como espacios en blanco y Celiminar comentarios del shell) y eliminar una capa de comillas con el Qindicador de expansión de parámetros.

Luego puedes pasar esos tokens a algo que pueda codificar json (ocúpate de los caracteres de control, incluidos nueva línea, barra invertida, "caracteres, etc.):

perl -CA -MJSON -le '
  for (@ARGV) {
    if (/(.*?)=(.*)/s) {
      $h{$1} = $2;
    }
  }
  print encode_json \%h' -- $tokens

Por ejemplo, uno filecomo:

var1='a random text' # comment
var2='another'\'' random text'
var3='a third random text'

name=$'St\u00e9phane Chazelas'
empty=
at=@
more=broken\
down"with 1 \\ backslash"
numstring=1.1

Da:

{"numstring":"1.1","name":"Stéphane Chazelas","empty":"","more":"brokendownwith 1 \\ backslash","var1":"a random text","at":"@","var2":"another' random text","var3":"a third random text"}

información relacionada