You're making it a lot more complicated than it is. Just use map() and |=:
jq 'map(.tags |= split(" "))' file.json
Edit:
If you want to handle entries without tags:
jq 'map(try(.tags |= split(" ")))' file.json
Alternatively, if you want to keep unchanged all entries without tags:
jq 'map(try(.tags |= split(" ")) // .)' file.json
Result:
[
{
"tags": [
"tagA",
"tag-B",
"tagC"
],
"title": "Some Title"
},
{
"tags": [
"tagA",
"tagC"
],
"title": "Some Title 2"
}
]
Answer from Satō Katsura on Stack ExchangeHow to use jq to convert an bash array in command line to json array? - Unix & Linux Stack Exchange
Creating an array from objects?
How to convert string list to JSON string array in Bash? - Stack Overflow
Raw lines to an array of lines?
You're making it a lot more complicated than it is. Just use map() and |=:
jq 'map(.tags |= split(" "))' file.json
Edit:
If you want to handle entries without tags:
jq 'map(try(.tags |= split(" ")))' file.json
Alternatively, if you want to keep unchanged all entries without tags:
jq 'map(try(.tags |= split(" ")) // .)' file.json
Result:
[
{
"tags": [
"tagA",
"tag-B",
"tagC"
],
"title": "Some Title"
},
{
"tags": [
"tagA",
"tagC"
],
"title": "Some Title 2"
}
]
You can attempt this is sed as follows:
The code below is using GNU version of sed (although it can be portably written in POSIX-compatible as well)
sed -e '
/[{]/,/[}]/!b
/"tags":/!b
h;s/"tags":/&\n/;s/\n.*/ /;s/./ /g;x
s/"tags":/&\n/
:a
s/\(\n.*\)\([^"]\) \([^"]\)/\1\2","\3/;ta
y/\n/[/;s/$/]/;G
:b
s/","\(.*\)\(\n.*\)/",\2"\1\2/;tb
s/\(.*\)\n.*/\1/
' yourjsonfile
Working
- We select the range as
{to the next}lines. - Zoom in on
"tags"line in the range selected. - Compute the nesting spaces for the given tag and store it in hold.
- Double quote the tag data in a loop
:a - Insert the nesting spaces after the
,in a loop:b - Remove everything after the last newline in the pattern space & print.
Results
[
{
"title": "Some Title",
"tags":["tagA",
"tag-B",
"tagC"]
},
{
"title": "Some Title 2",
"tags":["tagA",
"tagC"]
},
...
]
This trick with the jq 1.5 inputs streaming filter seems to do it
... | jq -n '.items |= [inputs]'
Ex.
$ find ~/ -maxdepth 1 -name "D*" |
while read line; do
jq -n --arg name "$(basename "$line")" \
--arg path "$line" \
'{name: $name, path: $path}'
done | jq -n '.items |= [inputs]'
{
"items": [
{
"name": "Downloads",
"path": "/home/steeldriver/Downloads"
},
{
"name": "Desktop",
"path": "/home/steeldriver/Desktop"
},
{
"name": "Documents",
"path": "/home/steeldriver/Documents"
}
]
}
Calling jq directly from find, and then collecting the resulting data with jq to construct the final output, without any shell loops:
find ~ -maxdepth 1 -name '[[:upper:]]*' \
-exec jq -n --arg path {} '{ name: ($path|sub(".*/"; "")), path: $path }' \; |
jq -n -s '{ items: inputs }'
The jq that is being executed via -exec creates a JSON object per found pathname. It strips off everything in the pathname up to the last slash for the name value, and uses the pathname as is for the path value.
The final jq reads the data from find into an array with -s, and simply inserts it as the items array in a new JSON object. The final jq invocation could also be written jq -n '{ items: [inputs] }.
Example result (note that I was using [[:upper:]* in place of D* for the -name pattern with find):
{
"items": [
{
"name": "Documents",
"path": "/home/myself/Documents"
},
{
"name": "Mail",
"path": "/home/myself/Mail"
},
{
"name": "Work",
"path": "/home/myself/Work"
}
]
}