interpolación de cadenas preservando comillas en bash

interpolación de cadenas preservando comillas en bash

Tengo que formatear el cuerpo de un json que obtiene algunos valores sustituidos por variables de entorno del usuario. Tratando de encontrar una manera a través de shopt o algo así para que la cadena json se sustituya correctamente en el script bash pero conserve/devuelva las comillas dobles para que sea un json válido. Intenté preprocesar citas y comillas dobles.

Ejemplo:

$ export env_var1=val1
$ export env_var2=val2
$ export args='{"key1": "${env_var1}", "key2": "${env_var2}"}'
$ echo $args #original input
$ eval echo $args #bad output- variables interpolated but quotes lost
Expected output= {"key1": "val1", "key2": "val2"}

Editar: Mi restricción aquí es que no conozco la cadena json arbitraria de antemano y no puedo reformatearla manualmente porque no conozco la estructura o los nombres de antemano. no necesito resolveresteCaso específico: es un ejemplo de juguete. Estoy intentando formular una solución genérica para una cadena arbitraria de la cual el ejemplo es representativo. Las claves, los valores o ambos podrían ser variables env. El json podría estar anidado arbitrariamente y ser grande.

Respuesta1

Podrías escapar de las comillas:

{\"key1\": \""$env_var1"\", "key2": \""$env_var2"\"}

Podrías usar jq:

jq -n --arg one "$env_var1" --arg two "$env_var2" '{key1: $one, key2: $two}'

Ojo:

jo key1="$env_var1" key2="$env_var2"

A menudo uso heredocs para objetos json complejos:

read -rd '' json <<EOF
{
    key1: "$env_var1",
    key2: "$env_var2"
}
EOF
echo "$json"

Respuesta2

En principio, con esas variables exactas, podrías usar envsubst:

$ export env_var1=val1
$ export env_var2=val2
$ export args='{"key1": "${env_var1}", "key2": "${env_var2}"}'
$ echo "$args" | envsubst
{"key1": "val1", "key2": "val2"}

Pero tenga en cuenta que a) expandirá cualquier variable de entorno, no solo las que coincidan env_*, y b) no citará ninguno de los contenidos para convertirlos en JSON válido. Por ejemplo, con env_var1='double"quote'"obtienes {"key1": "double"quote", ..." con comillas entrecortadas.

Para solucionar el primer problema, puede hacer algo como esto en Bash, para obtener una cadena que contenga una lista de los nombres de las variables que coinciden env_*con envsubst:

$ echo "$args" | envsubst "$(printf '$%s ' "${!env_@}")"
{"key1": "val1", "key2": "val2"}

(El problema es que requiere los $carteles principales).

Para el segundo, tendría que preprocesar las variables antes de pasarlas a envsubst, o pasarlas a través de jq.

Algo como esto generaría --argopciones para jqtodas las variables denominadas like env_*y cambiaría cualquiera "${foo}"de la cadena de entrada para $fooque jqlas reconozca como variables (tenga en cuenta que también cambiaría cualquier cadena coincidente no relacionada):

#!/bin/bash

args=(); 
for varname in "${!env_@}"; do
    args+=(--arg "$varname" "${!varname}");
done;
jq -n -c -M "${args[@]}" "$(sed -E -e 's/"\$\{([a-zA-Z0-9_]+)\}"/$\1/g' <<< "$1")"

Corre con:

$ export env_var1='double"quote' env_var2=foobar
$ bash jsonexpand.sh '{"key1": "${env_var1}", "key2": "${env_var2}"}'
{"key1":"double\"quote","key2":"foobar"}

Respuesta3

Debe citar la expresión para que el shell no la analice. En el caso trivial,

echo '{"key1": "var1", "key2": "var2"}'

En su caso, donde necesita interpolación de variables, cualquiera de estas opciones puede funcionar

printf '{"key1": "%s", "key2": "%s"}\n' "$env_var1" "$env_var2"
echo "{\"key1\": \"$env_var1\", \"key2\": \"$env_var2\"}"
echo '{"key1": "'"$env_var1"', "key2": "'"$env_var2"'"}'

Probablemente recomendaría el primero de ellos como el más legible.

información relacionada