Home > Software engineering >  Assign string with spaces to variable and escape those spaces
Assign string with spaces to variable and escape those spaces

Time:10-19

I'm trying to get some json data using jq:

{
    "meta": {
        "title": "This is a title",
        "description": "Just a description"
    }
}

by running jq -r '.meta | .title, .description' ./project.json, which gives me the expected result:

This is a title
Just a description

Now I need to assign the content to a variable in my bash script:

read TITLE DESCRIPTION < <(echo $(jq -r '.meta | .title, .description' ./project.json))

But this is not working because of the spaces. Also later I have to escape all spaces, which I would do with:

echo ${TITLE// /\\ }

How should I handle the assignment of the variable (handling space content) and escape the spaces (maybe in one step)?

CodePudding user response:

No, you don't need to escape anything here.

Using NULs to delimit all values, so we can correctly support titles or descriptions that contain newlines:

{
  IFS= read -r -d '' title
  IFS= read -r -d '' description
} < <(jq -r '.meta | (.title, .description) | (., "\u0000")' )

If we assume that title and description cannot contain literal newlines, either of the below will do:

{
  IFS= read -r title
  IFS= read -r description
} < <(jq -r '.meta | .title, .description' ./project.json)

...or, telling read to look for a terminating NUL, and thereby ensuring that it has a nonzero exit status should jq fail (but still using a newline to separate the two values):

IFS=$'\n' read -r -d '' title description < <(
  jq -r '.meta | (.title, .description, "\u0000")' ./project.json
)

Taking advantage of jq's support for generating sh-compatible eval-safe escaping, we can also do the following, which does correctly handle strings with newlines:

eval "$(jq -r '
  .meta | "description=\(.description|@sh); title=\(.title|@sh)"
' ./project.json)"

CodePudding user response:

With builtin mapfile, bash and an array (title):

mapfile -t title < <(jq -r '.meta | .title, .description' project.json)
echo "${title[0]}"
echo "${title[1]}"

Output:

This is a title
Just a description

CodePudding user response:

Using some parameter substitutions:

$ x=$(jq ... )
$ title="${x%$'\n'*}"
$ description="${x#*$'\n'}"
$ typeset -p title description
declare -- title="This is a title"
declare -- description="Just a description"
  • Related