Определите переменные с именем переменной

11

Что не так с этим скриптом? Я пытаюсь определить A1 = 1, B1 = 1, C1 = 1

LIST="A B C"
for x in $LIST
do
    "$x"1=1
done

и результат:

./x.: line 7: A1=1: command not found
./x.: line 7: B1=1: command not found
./x.: line 7: C1=1: command not found
Аке Бломберг
источник
1
Я не думаю, что вы можете создавать переменные в Bash, как это. Это то, что для массивов.
Jakuje
3
Использование eval "$x"1=1. Хотя, как отметил Jakuje, массивы, вероятно, лучше подходят для этого случая.
Андреа Корбеллини
@AndreaCorbellini Вы должны написать это в качестве ответа.
Sparhawk

Ответы:

21

Присвоение переменной имеет вид имени переменной, за которым следует знак равенства, за которым следует (необязательное) значение.

Это действительное назначение:

ABC=123

"$x"1=1не является допустимым назначением, потому что "$x"1не является именем переменной. Это может быть Eval закончил институт по имени переменной, но это не так . Оболочка, на самом деле, считает, что это команда.

Один из способов сделать то, что вы хотите достичь, это:

eval "$x"1=1

Другой способ в bash (но не в других оболочках):

declare "$x"1=1

Или также (снова только bash):

let "$x"1=1

(В вашем случае нет большой разницы.)

Но, как отметил Jakuje в комментариях , вы, вероятно, захотите использовать массивы, если они есть в вашей оболочке (ksh, bash или zsh).


Для полноты:

  • evalвыполняет произвольные команды. Таким образом, если справа от знака равенства у вас есть переменная, которая расширяется до некоторой команды, эта команда будет выполнена. Следующий код:

    x=a
    y='$(echo hello)'
    eval "$x=$y"
    

    эквивалентно a=hello.

  • declareявляется встроенным в bash для назначения переменных и не выполняет никаких команд. Следующий код:

    x=a
    y='$(echo hello)'
    declare "$x=$y"
    

    эквивалентно a='$(echo hello)'.

  • letпохоже на то declare, что он не выполняет команды. Но вопреки declare, letможет использоваться для арифметических операций:

    let a="1 + 2"

    эквивалентно a=3.

Андреа Корбеллини
источник
Даже ABC = 123недействительно. Потому что пространство добавляется до и после equal(=)знака.
Махендран Саккарай
3

В bash FAQ есть запись о косвенности. В большинстве случаев вы должны использовать ассоциативный или индексированный массив. Вы также можете использовать

func_call_by_reference() { # Bash 4.3
    typeset -n ref=$1   # nameref to the variable named by the caller
    ref=( "val1" "val2" ... )  # return an array by reference
}

Посмотрите в этом разделе часто задаваемые вопросы больше возможностей для этого, избегая при этом беспорядочного evalцитирования.

Питер Кордес
источник
0

Вы можете использовать код, как показано ниже. В вашем коде оболочка выполняется "$x"1=1как команда, потому что она не является допустимым назначением переменной.

LIST="A B C"
for x in $LIST
do
    a=$(echo "$x"1)
    let $a=1
done
AVJ
источник
Какую оболочку вы используете? Используя bosh bash 4.1.7 и 4.3.11, я получаю сообщения об ошибках, command not found <varname>=1когда пытаюсь это сделать (очевидно, с <varname>, являющимся значением, в котором я хранил a)
Эрик Ренуф,
как объясняет @Andrea Corbellini, мы должны использовать let,
Declare
1
тебе echoздесь не нужно ! Просто a="$x"1. Также letявляется арифметическим контекстом, поэтому вы можете назначать только числа с ним.
Питер Кордес
declare $a=foobarработает.
Питер Кордес