Dynamic variable names in Bash

2018-12-31 03:04发布

I am confused about a bash script.

I have the following code:

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

I want to be able to create a variable name containing the first argument of the command and bearing the value of e.g. the last line of ls.

So to illustrate what I want:

$ ls | tail -1
stack-overflow.txt

$ grep_search() open_box
stack-overflow.txt

So, how should I define/declare $magic_way_to_define_magic_variable_$1 and how should I call it within the script?

I have tried eval, ${...}, \$${...}, but I am still confused.

10条回答
像晚风撩人
2楼-- · 2018-12-31 03:36

Use an associative array, with command names as keys.

# Requires bash 4, though
declare -A magic_variable=()

function grep_search() {
    magic_variable[$1]=$( ls | tail -1 )
    echo ${magic_variable[$1]}
}

If you can't use associative arrays (e.g., you must support bash 3), you can use declare to create dynamic variable names:

declare "magic_variable_$1=$(ls | tail -1)"

and use indirect parameter expansion to access the value.

var="magic_variable_$1"
echo "${!var}"

See BashFAQ: Indirection - Evaluating indirect/reference variables.

查看更多
查无此人
3楼-- · 2018-12-31 03:36

For indexed arrays, you can reference them like so:

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

Associative arrays can be referenced similarly but need the -A switch on declare instead of -a.

查看更多
泪湿衣
4楼-- · 2018-12-31 03:41

Example below returns value of $name_of_var

var=name_of_var
echo $(eval echo "\$$var")
查看更多
时光乱了年华
5楼-- · 2018-12-31 03:45

As per BashFAQ/006, you can use read with here string syntax for assigning indirect variables:

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

Usage:

$ grep_search open_box
$ echo $open_box
stack-overflow.txt
查看更多
余欢
6楼-- · 2018-12-31 03:47

I've been looking for better way of doing it recently. Associative array sounded like overkill for me. Look what I found:

suffix=bzz
declare prefix_$suffix=mystr

...and then...

varname=prefix_$suffix
echo ${!varname}
查看更多
长期被迫恋爱
7楼-- · 2018-12-31 03:49

Wow, most of the syntax is horrible! Here is one solution with some simpler syntax if you need to indirectly reference arrays:

#!/bin/bash

foo_1=("fff" "ffffd") ;
foo_2=("ggg" "ccc") ;

for i in 1 2 ;
do
    eval mine=( \${foo_$i[@]} ) ;
    echo ${mine[@]} ;
done ;

For simpler use cases I recommend the syntax described in the Advanced Bash-Scripting Guide.

查看更多
登录 后发表回答