コマンドラインを使用して、複数の変数をリストしたファイルを JSON に直接変換できますか?

コマンドラインを使用して、複数の変数をリストしたファイルを JSON に直接変換できますか?

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) )'

これは最初にjoJSONドキュメントを作成するために使用します

{
   "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=~/foovar2=$var1実行var3=$(uname)できます。

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

そのファイルの内容をシェル構文に従ってトークン化し (パラメータ拡張フラグを使用し、引用符で囲まれていない改行を空白と見なし、シェルのコメントを削除するように でz調整)、パラメータ拡張フラグを使用して引用符の 1 つのレイヤーを削除します。Z[flags]nCQ

次に、これらのトークンを、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"}

関連情報