Digamos que eu tenha um file
com 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 eval
a seguir, armazenarei todas essas variáveis diretamente no meu shell:
$ eval $(cat file)
Fazendo isso, meu shell irá criar $var1
, $var2
e $var3
com 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 eval
faz 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 jq
deaqui), 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 jo
para 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 jq
ferramenta é 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 z
sinalizador de expansão de parâmetro, ajustado (com Z[flags]
) para n
considerar novas linhas sem aspas como espaços em branco e C
remover comentários do shell) e remover uma camada de aspas com o Q
sinalizador 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 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
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"}