file
次のような内容の があるとします。
var1='a random text'
var2='another random text'
var3='a third random text'
次のようなコマンドを使用すると、eval
すべての変数がシェルに直接保存されることがわかっています。
$ eval $(cat file)
これを行うと、シェルは$var1
、それぞれの内容を含む、$var2
およびを作成します$var3
。これを知っていれば、次のように JSON を手動で生成できます。
$ JSON="{ \"var1\" : \"$var1\", \"var2\" : \"$var2\", \"var3\" : \"$var3\"}"
結果は有効な JSON になります:
$ echo $JSON
{ "var1" : "a random text", "var2" : "another random text", "var3" : "a third random text"}
ここでの問題は、キー var1、var2、var3 をハードコーディングしていることです... 私の場合、ファイルはより大きくなり、より多くの変数 (var1、var2、var3 だけでなく) が保存される可能性があります。eval
シェルにファイル変数を保存するのと同じように、コマンド ラインを使用して、変数を保存する代わりに JSON 出力を生成する簡単な方法があるかどうか考えていました。それは可能ですか? コマンド ラインを使用して、そのように構造化されたファイルを JSON に直接変換できますか?
ここでの私の代替解決策は、このファイル内の文字ごとにコード(シェルを使用せずに)を開発し、ループ内ですべてを動的に分離することです。しかし、解決策が複雑になりすぎないようにしたいので、この質問をしています。
答え1
jo
(からの組み合わせを使用してここ)とjq
(からここ)、シェル変数を作成したり、シェルにファイルを解釈させたりせずに実行します。
jo <file |
jq --arg sq "'" '.[] |= ( ltrimstr($sq) | rtrimstr($sq) )'
これは最初にjo
JSONドキュメントを作成するために使用します
{
"var1": "'a random text'",
"var2": "'another random text'",
"var3": "'a third random text'"
}
(ただし、1 行で)。これは、ファイル内の変数の割り当てをキーと値のペアとして解釈することによって行われます。
次に、このjq
ツールを使用して、各値の先頭と末尾から一重引用符を削除します。
最終結果は
{
"var1": "a random text",
"var2": "another random text",
"var3": "a third random text"
}
これは、値に埋め込まれた改行には対応しません。ただし、他の特殊文字は によって自動的に JSON エンコードされますjo
。
答え2
を使用しzsh
、ファイルが の構文と互換性のある構文でありzsh
、ファイルがシェルの拡張機能 ( 、、... など) を使用しておらず、値が UTF-8 でエンコードされたテキストであると仮定すると、次のようvar1=~/foo
にvar2=$var1
実行var3=$(uname)
できます。
tokens=( ${(Q)${(zZ[nC])"$(<file)"}} )
そのファイルの内容をシェル構文に従ってトークン化し (パラメータ拡張フラグを使用し、引用符で囲まれていない改行を空白と見なし、シェルのコメントを削除するように でz
調整)、パラメータ拡張フラグを使用して引用符の 1 つのレイヤーを削除します。Z[flags]
n
C
Q
次に、これらのトークンを、JSON をエンコードできるものに渡すことができます (改行、バックスラッシュ、"
文字などの制御文字に注意してください)。
perl -CA -MJSON -le '
for (@ARGV) {
if (/(.*?)=(.*)/s) {
$h{$1} = $2;
}
}
print encode_json \%h' -- $tokens
たとえば、次file
のようなものがあります。
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
それは与えます:
{"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"}