シェルスクリプトを使用して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
この点ではエコーよりも役に立ちます。過度の重複を防ぎ、コードを短くするには、関数を使用してください。
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
行ストリームを読み取るために使用され、各行にはタブ文字で区切られたキーと値があります。各行は式$line
のように読み取られ使用されますjq
。タブに分割して、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
各キーをその値に関連付ける長いコマンドラインを作成できます--arg
。jq
$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
。代わりに、このバリアントはコマンドラインで許可される最大長に制限され、通常この長さははるかに短いです。利点は、この最新のスクリプトが改行を含むすべての文字を含む値を処理することです。