JSONの正しい構造

JSONの正しい構造

シェル スクリプトを使用して JSON ファイルを生成していますが、末尾の "}" の直前の最後のコンマを自動的に削除する解決策が見つかりません。

これが私のコードです:

echo "{" >> out_file
for i in 3 4 5 6 7 #ends at 298
do
y=$i
sommeMag=`awk -F '=' '/'$y'/{sommeMag+=$2}END{print sommeMag}'` "/myfolder/... "
store="mag$y"
if [ -z "$sommeMag" ] #checks is variable is empty
    then
        echo  "\"" $store"\"":0",">> out_file
    else
        echo "\""$store"\"":$sommeMag"," >> out_file
    fi
done
echo "}" >> out_file

ファイルは次のように終わります:

{
" mag297":0,
" mag298":0, <-- syntaxt error
}

ファイルは次のように終わる必要があります:

{
...
" mag297":0,
" mag298":0 <-- no more comma
}

どうすればそれを管理できるでしょうか?

ここでは、コードが読みやすくなるように編集されています。

答え1

やるべきことは、最初の項目を印刷して、カーソルを停止することです。その後、ループを開始し、コンマと改行を挿入してカーソルを進めることができます。printfその点では echo よりも便利です。過度の繰り返しを防ぎ、コードを短くするには、関数を使用します。

awk で解析しているファイルを持っていないので、スクリプトを操作することはできませんが、以下の例は私が伝えようとしていることを示しています。

#!/bin/bash

print_entry(){
    # sommeMag would be variable $2, $1 is store
    if [ -z $2 ]
    then
        printf '"%s":0' "$1" 
    else
        printf '"%s":%s' "$1" "$2"
    fi
}

# main part of the script
printf "%s\n" "{"

# do the first one unconditionally but without comma
print_entry "something1" "something2"
for i in 2 3 4 5
do
    # because first one was printed unconditionally
    # now we just keep printing comma and moving cursor
    # to newline to insert the new entry
    printf ",\n"
    print_entry "something$i" "$i"
done
printf "\n%s"  "}"

サンプル実行

$ ./make_json.sh                                                                                                                                      
{
"something1":something2,
"something2":2,
"something3":3,
"something4":4,
"something5":5
}$ 

上記のアプローチは、私が「後ろにカンマを追加する」と呼んでいる典型的な方法です。別のアプローチは「前にカンマを追加する」ですが、for ループの代わりに、whileカウンター付きのループを使用して C スタイルの for ループの動作をシミュレートします。最後の項目に到達した場合は、カンマを出力しません。基本的に

counter=1
while [ $counter -le 298 ]
do
    $json_value=$(command1)
    if [ $counter -ne 298  ]
    then
        echo $json_value ,
    else
        echo $json_value
    fi 
    $counter=$(($counter+1))
done

答え2

#
# var initialzizations
#
# newline
NL=`printf '\nn'`;NL=${NL%?}

# double quote
q=\"

# separator set to a comma+newline
sep=",$NL"

# container for the json result
json=;

# begin/end of count values
start=3
 stop=7

# looping
# in case seq utility not found, then you can use: yes | sed -ne "$start,$stop=;${stop}q"
for i in `seq "$start" "$stop"`
do
   y=$i
   sommeMag=`awk -F = "/$y/"'{sommeMag+=$2}END{print sommeMag}'` "/myfolder/... "
   store=mag$y
   json=${json:-}${json:+"$sep"}$q\ $store$q:${sommeMag:-0}
done

# remove the separtor from the end and also place a newline
json=${json%"$sep"}$NL

printf '{\n%s}\n' "$json" >> out_file

答え3

タブで区切られたキーと値のペアのストリームが与えられた場合、それらのキーと値を含む単一の JSON オブジェクトを構築します (データに実際のタブが含まれている場合は、データの一部ではない文字を使用します)。

for something something
do
    output key and value with a tab in-between
done |
jq -Rn 'reduce inputs as $line ({}; ($line|split("\t")) as [$key, $value] | . += {($key): $value})'

これはjq、タブ文字で区切られたキーと値を持つ行のストリームを読み取るために使用されます。各行は、式のように読み取られて使用されます$linejqタブ文字で分割され、ステートメントreduceが蓄積しているオブジェクトにキーと値が追加されます。新しいキーと値が追加されるにつれてオブジェクトが大きくなり、入力ストリームが終了すると、完成したオブジェクトが出力されます。

これは、表現をきれいに印刷したバージョンですjq

reduce inputs as $line ({}; 
    ($line | split("\t")) as [$key, $value] | 
    . += {($key): $value}
)

動作するサンプルスクリプト:

#!/bin/bash

for (( i = 1; i <= 10; ++i ))
do
        printf 'key%.2d\tvalue%.2d\n' "$i" "$i"
done |
jq -Rn 'reduce inputs as $line ({}; ($line|split("\t")) as [$key, $value] | . += {($key): $value})'

出力:

{
  "key01": "value01",
  "key02": "value02",
  "key03": "value03",
  "key04": "value04",
  "key05": "value05",
  "key06": "value06",
  "key07": "value07",
  "key08": "value08",
  "key09": "value09",
  "key10": "value10"
}

キーと値がそれほど多くない場合は、これを簡略化して、 をjq使用して各キーとその値を関連付ける非常に長いコマンドラインを作成し--argjqこれらを出力するように要求することができます (これらは内部構造内にあります$ARGS.named)。

#!/bin/bash

args=()
for (( i = 1; i <= 10; ++i ))
do
        printf -v key   'key%.2d'   "$i"
        printf -v value 'value%.2d' "$i"
        args+=( --arg "$key" "$value" )
done

jq -n "${args[@]}" '$ARGS.named'

この場合、出力は前のスクリプトの出力と同じになります。違いは、前のスクリプトが処理できるキーと値の数が、プロセスで使用できるメモリによって制限されることですjq。対照的に、このバリアントは、通常はるかに短いコマンド ラインの最大許容長によって制限されます。利点としては、この最新のスクリプトは、改行を含む任意の文字を含む値を処理することです。

関連情報