コマンドラインを使用して複数の変数を一覧表示するファイルを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'"
}

(しかし一行に)。これは、ファイルの変数割り当てをキーと値のペアとして解釈することによって行われます。

次に、このjqツールを使用して、各値の先頭と末尾の単一引用符を削除します。

最終結果は

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

これは値に含​​まれる改行文字に対処できません。ただし、他の特殊文字は.jsonによって自動的にエンコードされますjo

答え2

を使用し、zshファイル構文がの構文と互換性があり、ファイルがシェル拡張子zsh(たとえばvar1=~/foo、、、、var2=$var1... var3=$(uname))を使用せず、値がUTF-8でエンコードされたテキストであると仮定すると、次のようになります。 :

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

シェル構文に従ってファイルの内容を表示し(zパラメータ拡張フラグを使用して引用符のない改行を空白として処理し、シェルコメントを削除するようにZ[flags]調整(使用))、パラメータ拡張フラグを使用して引用符の1つのレイヤーを削除するします。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"}

関連情報