Shell : 在 for 循环中创建和分配变量

Shell : create and assign variables inside for loop

我有这个 shell 脚本;这是一个循环,每次结果都设置在变量 "a" 中:

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

我的目的是如何通过动态变量名称更改 "a" $item_MYPREFIX

(连接 :$item + _MYPREFIX )

这样我的代码就可以通用了,就像这样:

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

我将能够显示每个变量:echo $one_MYPREFIXecho $two_MYPREFIX ....

当然,它还不能正常工作

建议,改正它?

不需要 heredocs,试试这个。

#!/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[@]}"

输出

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,
    }

这确实不是最佳实践,但您可以(在 bash 中)这样做:

$ 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",
    }

我相信那里唯一的bash主义(除了数组的存在,但几个shells有数组)是${!...}间接的使用,但这只是为了输出并没有必要。但是,由于您使用的是支持数组的 shell,您最好根本不这样做。与其创建名为 "two_MYPREFIX" 的变量,不如创建一个数组并将该值存储在索引 2 中,或者使用关联数组并存储在索引 "two" 中。这比使用 eval.

干净得多

像这样尝试

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

但最好使用数组。

#!/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

使用关联数组。

declare -A foo

for item in "${names[@]}";
do 
 foo[$item]="{
          \"NAME\": \"${item}_ABC\",
          \"CHANGED\": \"${item}_CHANGING\",
          \"VERSION\": \"${item}_GC\"
    }"
done

Bash 没有 eval、没有关联数组和使用模板的解决方案:

#!/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[@]}"

输出:

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\"
}"