JSON 正确构造

JSON 正确构造

我正在使用 shell 脚本生成 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读取行流,每行都有一个由制表符分隔的键和值。每一行都按表达式$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。相反,此变体受到命令行允许的最大长度的限制,该长度通常要小得多。从好的方面来说,这个最新的脚本将处理包含任何字符的值,包括换行符。

相关内容