динамические (переменные) имена переменных bash

12

Я хочу динамически создавать последовательность строк, манипулируя массивом элементов и создавая некоторую арифметическую процедуру.

for name in FIRST SECOND THIRD FOURTH FIFTH; do
    $name = $(( $6 + 1 ))
    $name = "${$name}q;d"
    echo "${$name}"; printf "\n"
done

Желание результата будет ниже для $6равных 0.

1q;d
2q;d
3q;d
4q;d
5q;d

Но я получаю эту ошибку

reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution

Я думаю, это что-то простое. Раньше работал когда я делал что-то вроде

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"
Яннис Кристофакис
источник
1
Можете ли вы объяснить это немного лучше. Не очень понимаю, что ты пытаешься сделать.
Нейрон
Что должен делать `$ name = $ (($ 6 + 1))`?
PSkocik
@PSkocik Я надеялся сделатьFIRST=$(( $6 + 1 ))
Джаннис Кристофакис

Ответы:

16

Прежде всего, не может быть пробела =в объявлении переменной в bash.

Чтобы получить то, что вы хотите, вы можете использовать eval.

Например пример скрипта, подобного вашему:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    eval "$name"="'$(( $i + 1 ))q;d'"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

Печать:

1q;d
2q;d
3q;d
4q;d
5q;d

Используйте с evalосторожностью, некоторые люди называют это злом по какой-то уважительной причине.

declare будет работать тоже:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    declare "$name"="$(( $i + 1 ))q;d"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

также печатает:

1q;d
2q;d
3q;d
4q;d
5q;d
heemayl
источник
Для чего !нужен восклицательный знак printf '%s\n' "${!name}"?
Джаннис Кристофакис
1
Это называется непрямым расширением расширения bashпараметра ..
прочитайте
1
Bash также имеет более хорошую альтернативу declare/ eval: printf -v varname '%fmt' args. Некоторые внутренние функции завершения bash используют это для вызова по ссылке. (передать имя переменной для хранения).
Питер Кордес
Примечание: Использование declareтолько устанавливает переменную в локальной области, в то время как evalподход устанавливает ее глобально.
пользователь
11

Если вы хотите сослаться на переменную bash, сохраняя имя в другой переменной, вы можете сделать это следующим образом:

$ var1=hello
$ var2=var1
$ echo ${!var2}
hello

В этом случае вы сохраняете имя переменной, к которой хотите получить доступ, например, var2. Затем вы обращаетесь к нему с помощью переменной ${!<varable name>}where <variable name>, содержащей имя переменной, к которой вы хотите получить доступ.

Эрик Ренуф
источник
Есть портативный способ, eval var=\$$holderно evalэто опасно!
gavenkoa
1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

Это то, что вы пытаетесь?

нейрон
источник
1

Что я получаю из вашего кода и желаемого результата (поправьте меня, если я ошибаюсь):
имена переменных "FIRST" / "SECOND" / ... не используются, вам просто нужен цикл с индексом .. ,

Это сделает работу:

for i in {1..5} ; do echo $i"q;d" ; done

CSNY
источник
Да, вы правы, кроме того, что я хочу сделать арифметическую функцию с переменной.
Джаннис Кристофакис
Можете ли вы привести пример этой арифметической функции? Вам нужно имя переменной (например, «THIRD») для нее или просто значение индекса?
csny
SUM=$(($6 + $i)); echo $SUM"q;d"Я вижу, что я делаю неправильно.
Джаннис Кристофакис