1

I am trying to receive output from an aws-cli command into Bash, and use it as an input to the second. I successfully saved the output into the variable with this helpful answer:

iid=$(aws ec2 run-instances ...)

and receive output like that:

{ "ImageId": "ami-0abcdef1234567890", "InstanceId": "i-1231231230abcdef0", "InstanceType": "t2.micro", ... }

I know that Bash since v4 supports associative arrays but I'm struggling converting one into one.

I tried to parse the dictionary in Bash but received error:

must use subscript when assigning associative array

This is because the right key syntax for Bash dicts is =, not :.

Finally I accessed the members by using this marvelous answer with sed:

echo $iid|sed 's/{//g;s/}//g;s/"//g'|cut -d ':' -f2

My question: is there any standard way of creating a Bash dictionary from JSON or text besides regex? Best-practice?

Considering the snippet from the answer I used, the sed-approach can be very verbose and the verbosity increases exponentially with the number of keys/members:

for items in `echo $db|sed 's/{//;s/}//'`
do
        echo one${count} = `echo $items|sed 's/^.*\[//;s/\].*$//'|cut -d ',' -f1`
        echo two${count} = `echo $items|sed 's/^.*\[//;s/\].*$//'|cut -d ',' -f2`
        echo three${count} = `echo $items|sed 's/^.*\[//;s/\].*$//'|cut -d ',' -f3`
        echo four${count} = `echo $items|sed 's/^.*\[//;s/\].*$//'|cut -d ',' -f4`
        ...
done

For simple dicts it is OK, but for the complex dictionaries with hundreds of keys and a big nesting level it is almost inapplicable.

Is there any unified approach for arbitrary dictionary?

P.S. I found answers about solving the opposite (receiving Bash dict in Python), solving the task through jq, creating dict from Bash to Bash and from non-common input but nothing about specifically JSON. I prefer not to use jq and python and stick to the standard Bash toolset, most of the answers of this collective answer use 3rd-party tools. Is it possible at all?

Suncatcher
  • 10,355
  • 10
  • 52
  • 90
  • I'd use `jq` to extract the relevant information from the json. – choroba Dec 03 '20 at 12:17
  • What are you looking to do with the array? – Raman Sailopal Dec 03 '20 at 12:38
  • Accessing the members and modifying them (swapping, replacing) – Suncatcher Dec 03 '20 at 12:39
  • @Suncatcher `jq` \(*if working from shell only*) is capable of doing all what you mention. Now if you have access to python or perl, manipulationg JSON objects from there, may be more natural than using the unique `jq`'s language, that can take a while to understand and master. – Léa Gris Dec 03 '20 at 12:57
  • There is a significant difference between JSON objects and `bash` associative arrays. An associative array can only have *strings* as values, not other arrays. If you want to work with JSON, `bash` is the wrong language to use. – chepner Dec 03 '20 at 13:23
  • There is a Python package that wraps `libjq`, so you can use `jq` filters in Python in the cases where they *are* more natural to use. – chepner Dec 03 '20 at 13:24
  • `If you want to work with JSON, bash is the wrong language to use` Okay, clear. If it is non-natural, probably it's worth putting into answer to highlight that approach is wrong. – Suncatcher Dec 03 '20 at 13:40

1 Answers1

3

One way to turn your JSON object members into a Bash4+'s associative array:

#!/usr/bin/env bash

# shellcheck disable=SC2155 # Associative array declaration from JSON
declare -A assoc=$(
  jq -r '"(",(to_entries | .[] | "["+(.key|@sh)+"]="+(.value|@sh)),")"' \
  input.json
)

# Debug dump the Associative array declaration
typeset -p assoc

Sample output:

declare -A assoc=([InstanceId]="i-1231231230abcdef0" [InstanceType]="t2.micro" [ImageId]="ami-0abcdef1234567890" )
Léa Gris
  • 17,497
  • 4
  • 32
  • 41