Estou gerando um arquivo JSON com um script de shell, mas não consigo encontrar uma solução para me livrar automaticamente da última vírgula antes do final "}".
Aqui está o meu código:
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
O arquivo está terminando assim:
{
" mag297":0,
" mag298":0, <-- syntaxt error
}
O arquivo deve terminar assim:
{
...
" mag297":0,
" mag298":0 <-- no more comma
}
Como posso gerenciar isso?
O código foi editado para ser mais legível aqui.
Responder1
O que você deveria fazer é imprimir o primeiro item e deixar o cursor parar. Então você pode começar a trabalhar no loop e avançar o cursor inserindo vírgula e nova linha. printf
é mais útil do que echo nesse sentido. Para evitar repetições excessivas e encurtar o código, use funções.
Como não tenho os arquivos que você está analisando com o awk, não posso trabalhar com seu script, mas o exemplo abaixo ilustra o que estou tentando transmitir.
#!/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" "}"
Execução de amostra
$ ./make_json.sh
{
"something1":something2,
"something2":2,
"something3":3,
"something4":4,
"something5":5
}$
A abordagem acima é normalmente o que chamo de "adicionar vírgula atrás". Outra abordagem seria "Adicionar vírgula à frente", mas em vez de loop for, use while
loop com contador para simular o comportamento do loop for no estilo C. Se você chegar ao último item, não digite vírgula. Basicamente
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
Responder2
#
# 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
Responder3
Dado um fluxo de pares de chaves e valores delimitados por tabulações, construa um único objeto JSON contendo essas chaves e valores. (Se os dados contiverem tabulações reais, basta usar um caractere que não faça parte dos dados.)
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})'
É usado jq
para ler um fluxo de linhas, cada uma com uma chave e um valor separados por um caractere de tabulação. Cada linha é lida e usada como $line
na jq
expressão. Ele é dividido no caractere de tabulação e a chave e o valor são adicionados ao objeto que a reduce
instrução está acumulando. O objeto cresce à medida que novas chaves e valores são adicionados e, quando o fluxo de entrada termina, o objeto finalizado é gerado.
Esta é uma versão bem impressa da jq
expressão:
reduce inputs as $line ({};
($line | split("\t")) as [$key, $value] |
. += {($key): $value}
)
Um script de exemplo funcional:
#!/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})'
Saída:
{
"key01": "value01",
"key02": "value02",
"key03": "value03",
"key04": "value04",
"key05": "value05",
"key06": "value06",
"key07": "value07",
"key08": "value08",
"key09": "value09",
"key10": "value10"
}
Se não houver muitas chaves e valores, podemos simplificar isso e apenas criar uma jq
linha de comando muito longa que associa cada chave ao seu valor usando --arg
e, em seguida, solicitar jq
a saída destes (que serão encontrados na $ARGS.named
estrutura interna):
#!/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'
Neste caso, a saída será idêntica à saída do script anterior. A diferença é que o número de chaves e valores com os quais o script anterior pode lidar é limitado pela memória disponível para o jq
processo. Em contraste, esta variante é limitada pelo comprimento máximo permitido da linha de comando, que geralmente é muito menor. Por outro lado, este script mais recente irá lidar com valores que contenham qualquer caractere, incluindo novas linhas.