简体   繁体   中英

exporting environment variables with spaces using jq

So, I'm trying to export an environment variable that comes from an api that returns json values. Would like to use jq to just do a one liner, but if the values have spaces I cannot get it working

Trying without surrounding the value in quotes

/app/src $ $(echo '{"params":[{ "Name":"KEY","Value":"value with space"}]}' | jq
 -r '.params[] | "export " + .Name + "=" + .Value')
/app/src $ printenv KEY
value
/app/src $ 

Next, I try wrapping the value in quotes

/app/src $ $(echo '{"params":[{ "Name":"KEY","Value":"value with space"}]}' | jq
 -r '.params[] | "export " + .Name + "=\"" + .Value + "\""')
sh: export: space": bad variable name
/app/src $ 

For all of the below, I'm assuming that:

json='{"params":[{ "Name":"KEY","Value":"value with space"}]}'

It can be done with eval , but ONLY IF YOU TRUST YOUR INPUT .

This might look like:

eval "$(jq -r '.params[] | "export \(.Name | @sh)=\(.Value | @sh)"' <<<"$json")"

The @sh builtin in jq escapes content to be eval -safe in bash, and the eval invocation then ensures that the content goes through all parsing stages (so literal quotes in the data emitted by jq become syntactic).


Better form is to generate a NUL-delimited key/value list...

build_kv_nsv() {
  jq -j '.params[] |
    ((.Name | gsub("\u0000"; "")),
     "\u0000",
     (.Value | gsub("\u0000"; "")),
     "\u0000")'
}

...and either populate an associative array...

declare -A content_received=( )
while IFS= read -r -d '' name && IFS= read -r -d '' value; do
  content_received[$name]=$value
done < <(build_kv_nsv <<<"$json")

# print the value of the populated associative array
declare -p content_received

...or to use a namespace that's prefixed to guarantee safety.

while IFS= read -r -d '' name && IFS= read -r -d '' value; do
  printf -v "received_$name" %s "$value" && export "received_$name"
done < <(build_kv_nsv <<<"$json")

# print names and values of our variables that start with received_
declare -p "${!received_@}" >&2

If the values are known not to contain (raw) newlines, and if you have access to mapfile , it may be worthwhile considering using it, eg

$ json='{"params":[{ "Name":"KEY","Value":"value with space"}]}'
$ mapfile -t KEY < <( jq -r '.params[] | .Value' <<< "$json" )
$ echo N=${#KEY[@]}
N=1

If the values might contain (raw) newlines, then you'd need a version of mapfile with the -d option, which could be used as illustrated below:

$ json='{"params":[{ "Name":"KEY1","Value":"value with space"}, { "Name":"KEY2","Value":"value with \n newline"}]}'
$ mapfile -d $'\0' KEY < <( jq -r -j '.params[] | .Value + "\u0000"' <<< "$json" )
$ echo N=${#KEY[@]}
N=2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM