I am trying make a bash script to get user input, format that input into a JSON, then post that JSON to a Firebase Realtime Database using the REST API. After getting the input, I use printf
statements to format the input into a JSON. The issue is that I have a trailing comma after the last entry in an array.
Here is the printf
statement to format the JSON
json=$(printf '{"itemName":"%s","images":[%s],"type":[%s],"link":"/"}' "$itemName" "$(printf '"%s",' "${imgArray[@]%,}")" "$(printf '"%s",' "${typeArray[@]}")")
Here is a sample output
{"itemName":"itemname","images":["url1","url2","url3",],"type":["all","hats",],"link":"/"}
I understand the training comma comes from the %s,
statement in the printf
.
Is there a way to modify the printf
statement to not use a comma at the last entry in the array? Or is there a way to use commands like sed
to remove that trailing comma?
2
Answers
Assumptions:
0
Sample inputs:
NOTE: While there may be a way to do this with a json tool (eg,
jq
), I’ll focus on some generalbash
capabilities …The general approach is to print the 1st element by itself, then preface the 2nd-nth elements with a comma.
Breaking the current
printf
calls into two parts:This (still) requires OP’s code to make 3 subprocess calls.
One idea to eliminate the subprocesses consists of using the (
bash
)printf
builtin to populate some variables (imgs
,types
,json
):This generates:
Install
jq
and use it to generate JSON files. Bash andsed
are not the right tools to manipulate JSON.In your case, building the JSON cannot be done in a single step. Let’s start with the list of images:
The
for
command above lists the items of the$ITEMS
Bash array variable one per line. The output is piped tojq
that processes it as follows:-s
tells it to "slurp" all the input data into an array instead of processing each line individually;-R
means "raw input"; combined withs
it tellsjq
to read the whole input in a big string and apply the program only once to it;-c
tells it to produce compact output (the entire JSON on a single line, without extra spaces).The short options can be combined into a single word.
-sRc
is the same as-s -R -c
.The
jq
program:The
jq
program basically does the opposite of thefor
loop but, very important, it processes raw data and produces a JSON (an array of strings).Assuming the array is initialized as:
… the script above produces:
This allows us to write a larger command line that does what you need:
The command line options:
-n
tellsjq
to not read anything fromstdin
;--arg
defines a variable (name
) whose value is a raw string, the next argument); Bash computes that argument by expanding"$itemName"
;--argjson
defines a variable (images
) whose value is a JSON;jq
parses this JSON before starting the execution of the program; "$(…)" produces the evaluation of the command between parentheses and the result is a single word; the command is the one described above, that produces an array encoded as JSON from a Bash array variable;{ itemName: $name, images: $images, type: $types, link: "/" }
is thejq
program; it produces an object having the keysitemName
,image
,type
andlink
, whose values are produced from the values of thejq
variables set using--arg
and--argjson
; the value oflink
is the string literal/
.All in all, this big command line that invokes
jq
three times does what you need and you don’t have to worry about trailing commas or other JSON details. All you need to care is about wrapping everything in quotes properly.Check it online.
Update
Because the code that renders
imgArray
into a JSON that encodes an array of strings runs in a sub-shell, we can change the IFS and use a singleecho
instead of afor
loop to get the same outcome faster:The complete script becomes:
It has the same output but it’s shorter and it should run faster. Check it oneline.