0

i ve this shell script ; it's a loop which set in the variable "a" each time result :

declare -a names=("one" "two" "three" "four")

    for item in "${names[@]}";
    do 
     a="$(cat <<-EOF
        {
          "NAME": "${item}_ABC",
          "CHANGED": "${item}_CHANGING",
          "VERSION": "${item}_GC",
        }
    EOF
    )"
    done
    echo $a

My Purpose is how to change "a" by a dynamic variable name which be $item_MYPREFIX

(concatination :$item + _MYPREFIX )

So that my code would be generic , something like this :

for item in "${names[@]}";
do 
 $item_MYPREFIX="$(cat <<-EOF
    {
          "NAME": "${item}_ABC",
          "CHANGED": "${item}_CHANGING",
          "VERSION": "${item}_GC",
    }
EOF
)"
done

and i would be able to display each variable : echo $one_MYPREFIX , echo $two_MYPREFIX ....

Of course it's not alerady working

Suggestions , to crrect it ?

4
  • That is perhaps the most ingenious UUOC I can remember seeing. You can simply assign a with a multiline string. as in: a=" {\n "NAME": "${item}..." (here, I use \n to indicate a newline that I cannot embed in the comment, rather than a literal \n to be expanded. Although you could also do a=$'{\n "NAME": "'"${item}_ABC"$'....) Commented Mar 5, 2020 at 12:11
  • no it' s not an UUOC i need it to format some json later .. my goal is how to create dynamically variables names Commented Mar 5, 2020 at 12:19
  • Yes, it is UUOC. If you are going to replace cat with something like jq, that's reasonable. But this usage of cat is useless. Commented Mar 5, 2020 at 12:24
  • I recommend a=$(jq -n --arg x "$item" '{NAME: "\($x)_ABC", CHANGED: "\($x)_CHANGING", VERSION: "\($x)_GC"}'); this ensures that the value of item is properly escaped, if necessary, to generate valid JSON. Commented Mar 5, 2020 at 12:40

5 Answers 5

2

Use an associative array.

declare -A foo

for item in "${names[@]}";
do 
 foo[$item]="{
          \"NAME\": \"${item}_ABC\",
          \"CHANGED\": \"${item}_CHANGING\",
          \"VERSION\": \"${item}_GC\"
    }"
done
Sign up to request clarification or add additional context in comments.

Comments

1

Try it like this

#!/bin/bash
for item in "${names[@]}"; do 
varname=${item}_MYPREFIX
declare $varname="
    {
          \"NAME\": \"${item}_ABC\",
          \"CHANGED\": \"${item}_CHANGING\",
          \"VERSION\": \"${item}_GC\",
    }
"
echo "${!varname}"
done

But better use arrays for that.

#!/bin/bash
declare -A array
names=("one" "two" "three" "four")
for item in "${names[@]}"; do 
indexname=${item}_MYPREFIX
array[$indexname]="
    {
          \"NAME\": \"${item}_ABC\",
          \"CHANGED\": \"${item}_CHANGING\",
          \"VERSION\": \"${item}_GC\",
    }
"
echo "${array[$indexname]}"
done

Comments

0

This is really not best practice, but you can (in bash) do:

$ cat a.sh
#!/bin/bash

declare -a names=("one" "two" "three" "four")

for item in "${names[@]}"; do
        eval "read -d '' ${item}_MYPREFIX" << EOF
    {
          "NAME": "${item}_ABC",
          "CHANGED": "${item}_CHANGING",
          "VERSION": "${item}_GC",
    }
EOF
done

for item in "${names[@]}"; do
        k="${item}_MYPREFIX"
        echo "$k = ${!k}"
done
$ ./a.sh
one_MYPREFIX = {
          "NAME": "one_ABC",
          "CHANGED": "one_CHANGING",
          "VERSION": "one_GC",
    }
two_MYPREFIX = {
          "NAME": "two_ABC",
          "CHANGED": "two_CHANGING",
          "VERSION": "two_GC",
    }
three_MYPREFIX = {
          "NAME": "three_ABC",
          "CHANGED": "three_CHANGING",
          "VERSION": "three_GC",
    }
four_MYPREFIX = {
          "NAME": "four_ABC",
          "CHANGED": "four_CHANGING",
          "VERSION": "four_GC",
    }

I believe the only bashism there (besides the existence of arrays, but several shells have arrays) is the usage of ${!...} indirection, but that's just for output and is not really necessary. However, since you're using a shell that supports arrays, you might as well not do this at all. Instead of creating a variable named "two_MYPREFIX", you ought to create an array and store that value in either index 2, or use an associative array and store in with index "two". That would be much cleaner than using eval.

1 Comment

`printf -v "${item}_MYPREFIX" $'{\n "NAME": "%s_ABC",\n "CHANGED": "%q",\n "VERSION": "%q"\n}\n' ...
0

The heredocs is not needed, try this.

#!/usr/bin/env bash

declare -a names=("one" "two" "three" "four")
declare -a prefix=(foo bar baz more)

for item in "${!names[@]}"; do
   array+=("${prefix[$item]} = {
      "NAME": "${names[$item]}_ABC",
      "CHANGED": "${names[$item]}_CHANGING",
      "VERSION": "${names[$item]}_GC",
    }"
   )
done

printf '%s\n' "${array[@]}"

Output

foo = {
      NAME: one_ABC,
      CHANGED: one_CHANGING,
      VERSION: one_GC,
    }
bar = {
      NAME: two_ABC,
      CHANGED: two_CHANGING,
      VERSION: two_GC,
    }
baz = {
      NAME: three_ABC,
      CHANGED: three_CHANGING,
      VERSION: three_GC,
    }
more = {
      NAME: four_ABC,
      CHANGED: four_CHANGING,
      VERSION: four_GC,
    }

1 Comment

that s not what i want , i want to send multiple variables for each loop cycle , and not insert it all in a
0

Bash solution without eval, without associative array and using a template:

#!/usr/bin/env bash

declare -a names=("one" "two" "three" "four")

read -r -d '' template <<'EOF'
{
    "NAME": "%q_ABC",
    "CHANGED": "%q_CHANGING",
    "VERSION": "%q_GC"
}
EOF

for item in "${names[@]}"; do
  # shellcheck disable=SC2059 # format with a template variable
  printf -v "${item}_MYPREFIX" "$template" "$item" "$item" "$item" 
done

# Dump variables for debug
IFS=$'\n' read -r -d '' -a k < <(printf '%s_MYPREFIX\n' "${names[@]}")
typeset -p "${k[@]}"

Output:

declare -- one_MYPREFIX="{
    \"NAME\": \"one_ABC\",
    \"CHANGED\": \"one_CHANGING\",
    \"VERSION\": \"one_GC\"
}"
declare -- two_MYPREFIX="{
    \"NAME\": \"two_ABC\",
    \"CHANGED\": \"two_CHANGING\",
    \"VERSION\": \"two_GC\"
}"
declare -- three_MYPREFIX="{
    \"NAME\": \"three_ABC\",
    \"CHANGED\": \"three_CHANGING\",
    \"VERSION\": \"three_GC\"
}"
declare -- four_MYPREFIX="{
    \"NAME\": \"four_ABC\",
    \"CHANGED\": \"four_CHANGING\",
    \"VERSION\": \"four_GC\"
}"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.