Digamos que tengo un file
con el siguiente contenido:
var1='a random text'
var2='another random text'
var3='a third random text'
Sé que si uso el comando eval
como el siguiente almacenaré todas esas variables directamente en mi shell:
$ eval $(cat file)
Al hacer eso, mi shell creará archivos $var1
, $var2
y $var3
con 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 eval
lo 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 jq
deaquí), 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 jo
para 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 jq
herramienta 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 z
indicador de expansión de parámetros, modificado (con Z[flags]
) con n
para considerar líneas nuevas sin comillas como espacios en blanco y C
eliminar comentarios del shell) y eliminar una capa de comillas con el Q
indicador 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 file
como:
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"}