我对bash脚本感到困惑。

我有以下代码:

function grep_search() {
    magic_way_to_define_magic_variable_$1=`ls | tail -1`
    echo $magic_variable_$1
}

我希望能够创建一个变量名,其中包含命令的第一个参数,并承载例如ls的最后一行的值。

为了说明我想要的:

$ ls | tail -1
stack-overflow.txt

$ grep_search() open_box
stack-overflow.txt

那么,我应该如何定义/声明$magic_way_to_define_magic_variable_$1,我应该如何在脚本中调用它?

我已经试过eval, ${…}, \$${...},但我还是很困惑。


当前回答

POSIX兼容的答案

对于这个解决方案,您需要拥有/tmp文件夹的r/w权限。 我们创建一个临时文件保存变量,并利用set内置的-a标志:

$ man套装 ... -a每个创建或修改的变量或函数都被赋予export属性,并标记为可导出到后续命令的环境。

因此,如果我们创建一个包含动态变量的文件,我们可以使用set在脚本中赋予它们生命。

实现

#!/bin/sh
# Give the temp file a unique name so you don't mess with any other files in there
ENV_FILE="/tmp/$(date +%s)"

MY_KEY=foo
MY_VALUE=bar

echo "$MY_KEY=$MY_VALUE" >> "$ENV_FILE"

# Now that our env file is created and populated, we can use "set"
set -a; . "$ENV_FILE"; set +a
rm "$ENV_FILE"
echo "$foo"

# Output is "bar" (without quotes)

解释以上步骤:

# Enables the -a behavior
set -a

# Sources the env file
. "$ENV_FILE"

# Disables the -a behavior
set +a

其他回答

根据BashFAQ/006,你可以使用read with here字符串语法来分配间接变量:

function grep_search() {
  read "$1" <<<$(ls | tail -1);
}

用法:

$ grep_search open_box
$ echo $open_box
stack-overflow.txt

这应该可以工作:

function grep_search() {
    declare magic_variable_$1="$(ls | tail -1)"
    echo "$(tmpvar=magic_variable_$1 && echo ${!tmpvar})"
}
grep_search var  # calling grep_search with argument "var"

这个也可以

my_country_code="green"
x="country"

eval z='$'my_"$x"_code
echo $z                 ## o/p: green

在你的情况下

eval final_val='$'magic_way_to_define_magic_variable_"$1"
echo $final_val

对于索引数组,你可以像这样引用它们:

foo=(a b c)
bar=(d e f)

for arr_var in 'foo' 'bar'; do
    declare -a 'arr=("${'"$arr_var"'[@]}")'
    # do something with $arr
    echo "\$$arr_var contains:"
    for char in "${arr[@]}"; do
        echo "$char"
    done
done

关联数组可以类似地引用,但需要在declare上使用-A开关而不是-A。

将两个评分较高的答案结合成一个完整的例子,希望有用且不言自明:

#!/bin/bash

intro="You know what,"
pet1="cat"
pet2="chicken"
pet3="cow"
pet4="dog"
pet5="pig"

# Setting and reading dynamic variables
for i in {1..5}; do
        pet="pet$i"
        declare "sentence$i=$intro I have a pet ${!pet} at home"
done

# Just reading dynamic variables
for i in {1..5}; do
        sentence="sentence$i"
        echo "${!sentence}"
done

echo
echo "Again, but reading regular variables:"
echo $sentence1
echo $sentence2
echo $sentence3
echo $sentence4
echo $sentence5

输出:

你知道吗,我家里有一只宠物猫 你知道吗,我家里有只宠物鸡 你知道吗,我家里有一头宠物牛 你知道吗,我家里有一只宠物狗 你知道吗,我家里有只宠物猪

同样,但是读取的是常规变量: 你知道吗,我家里有一只宠物猫 你知道吗,我家里有只宠物鸡 你知道吗,我家里有一头宠物牛 你知道吗,我家里有一只宠物狗 你知道吗,我家里有只宠物猪