6

I have a JSON file which contains the following (amongst other properties):

{
  "environment": "$USER"
}

I am extracting that value using jq like so:

ENVIRONMENT="$(jq -r '.environment' "properties.json")"

I want the value of ENVIRONMENT to be my username, not the string $USER - is this possible?

tedly
  • 37

4 Answers4

10

Option 1: Just read variable by name

bash allows having variables that reference variables, example:

REF='USER'  # or get it from JSON
echo "${!REF}"
# prints current username

So you can write this:

ENVIRONMENT_REF="$(jq -r '.environment' "properties.json")"
ENVIRONMENT="${!ENVIRONMENT_REF}"

JSON contents:

"environment": "USER"

Option 2: Full shell expansion

Other option, maybe better (but definitely NOT secure) is using eval:

ENVIRONMENT="$(eval "echo $(jq -r '.environment' "properties.json")")"

Note that this is not secure and malicious code can be inserted to the JSON file. What malicious code? Let's look into this properties.json file:

{
    "environment": "$(rm some_file)" 
}

The shell will evaluate this code:

echo $(rm some_file)

… and the file named some_file will be deleted. As you can see, depending on the command entered there, you can cause very serious damage.

jiwopene
  • 1,071
  • Thank you so much! I had come across option 1 but was missing the key part that the value in the JSON file must not have the $ symbol. Thanks for providing two options as well, and so quickly! – Stuart Leyland-Cole Feb 26 '21 at 17:52
  • @StuartLeyland-Cole, if you think this is the correct answer, click the icon on the left side. – jiwopene Feb 26 '21 at 17:53
  • 1
    @jiwopene and my thanks for the edit pointing out that eval is a security risk. It makes me feel better about upvoting :) Note that the system doesn't allow the asker to accept an answer in the first 15 minutes after posting, so Stuart cannot accept yet. – terdon Feb 26 '21 at 17:55
  • @terdon, added example of malicious code. – jiwopene Feb 26 '21 at 17:58
10

jq provides access to its environment via a $ENV object - similar to perl's $ENV hash or awk's ENVIRON associative array. So for example assuming (as suggested by the accepted answer) your properties.json file looks like

{
  "environment": "USER"
}

then you can do

$ environment="$(jq -r '$ENV[.environment]' properties.json)"
$ echo "$environment"
steeldriver

(best to avoid ALLCAPS for your shell variables). If your file looks like

{
  "environment": "$USER"
}

including the shell-expansion $ then you can use the same method after removing the $:

environment="$(jq -r '$ENV[.environment | sub("^\\$";"")]' properties.json)"

Alternatively, you could pipe the result of a simple lookup through the external envsubst command:

$ environment="$(jq -r '.environment' properties.json | envsubst)"
$ echo "$environment"
steeldriver

See for example Replace environment variables in a file with their actual values?

steeldriver
  • 81,074
1

This is just a slight re-write of one of the other answers.

In a Linux terminal, create a local folder:

$ mkdir -p ~/unix.se/jq/ && cd ~/unix.se/jq/

Create the file properties.json:

$ echo '{"environment":"USER"}'>properties.json && cat properties.json
{"environment":"USER"}

A side note - pretty formatting with jq:

$ jq '.' properties.json
{
  "environment": "USER"
}

Use the value of the JSON key environment, to set a new environment variable and show its contents: 1

$ JQ_USER=$(jq -r '$ENV[.environment]' properties.json) && echo $JQ_USER
tedly

So far so good, but the problem is that I have been lying.(!) - The properties.json file does not look quite as above, as it has a dollar sign in front of USER, like so:

$ echo '{"environment":"$USER"}'>properties.json && cat properties.json
{"environment":"$USER"}

By getting rid of that disturbing dollar sign, for example by substituting the empty string for it, we can get back to the already working solution:

$ JQ_USER=$(jq -r '$ENV[.environment | sub("\\$";"")]' properties.json)
echo $JQ_USER
tedly

1 When I first ran this, I got an error message starting with jq: error: ENV/0 is not defined at <top-level>. It turns out that $ENV[] requires version 1.6 (or later) of jq.

tedly
  • 37
0

One way can be as follows

ENVIRONMENT=$(printenv $(jq -r '.environment' properties.json |
cut -c2-))
guest_7
  • 5,728
  • 1
  • 7
  • 13