Posso converter diretamente um arquivo que lista múltiplas variáveis ​​em JSON usando a linha de comando?

Posso converter diretamente um arquivo que lista múltiplas variáveis ​​em JSON usando a linha de comando?

Digamos que eu tenha um filecom o seguinte conteúdo:

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

Eu sei que se eu usar o comando evala seguir, armazenarei todas essas variáveis ​​​​diretamente no meu shell:

$ eval $(cat file)

Fazendo isso, meu shell irá criar $var1, $var2e $var3com seus respectivos conteúdos. Sabendo disso, eu poderia gerar um JSON manualmente como o seguinte:

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

E isso resultaria em um JSON válido:

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

O problema aqui é que estou codificando as chaves var1, var2 e var3... No meu caso, o arquivo poderia ser maior e com mais variáveis ​​armazenadas nele (não apenas var1, var2 e var3). Eu estava pensando se existe uma maneira fácil de conseguir isso usando a linha de comando, assim como evalfaz para armazenar variáveis ​​de arquivo no shell, mas em vez de armazenar as variáveis, gerando uma saída JSON. É possível? Posso converter diretamente um arquivo estruturado dessa forma para JSON usando a linha de comando?


Minha solução alternativa aqui seria desenvolver um código (sem usar shell) que vá char por char dentro deste arquivo e então separe tudo dinamicamente em um loop. Mas estou fazendo essa pergunta porque quero evitar complicar demais a solução.

Responder1

Usando uma combinação de jo(deaqui) e jqdeaqui), sem criar variáveis ​​de shell ou deixar que o shell interprete o arquivo:

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

Isso é usado primeiro jopara criar o documento JSON

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

(mas em uma única linha). Isso é feito interpretando as atribuições de variáveis ​​em seu arquivo como pares de valores-chave.

A jqferramenta é então usada para excluir as aspas simples do início e do final de cada valor.

O resultado final é

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

Isso não funcionará com novas linhas incorporadas nos valores. No entanto, outros caracteres especiais serão automaticamente codificados em JSON por jo.

Responder2

Com zsh, e assumindo que o arquivo esteja em uma sintaxe compatível com a de zsh, que o arquivo não faça uso de recursos de expansão do shell (como var1=~/foo, var2=$var1, var3=$(uname)...) e que os valores sejam codificados em texto em UTF-8, você poderia fazer :

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

Para tokenizar o conteúdo desse arquivo de acordo com a sintaxe do shell (usando o zsinalizador de expansão de parâmetro, ajustado (com Z[flags]) para nconsiderar novas linhas sem aspas como espaços em branco e Cremover comentários do shell) e remover uma camada de aspas com o Qsinalizador de expansão de parâmetro.

Então você pode passar esses tokens para algo que possa codificar json (cuide dos caracteres de controle, incluindo nova linha, barra invertida, "caracteres, etc.):

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

Por exemplo, um 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

Dá:

{"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"}

informação relacionada