динамические (переменные) имена переменных 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

Для чего !нужен восклицательный знак 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


Да, вы правы, кроме того, что я хочу сделать арифметическую функцию с переменной.
Джаннис Кристофакис

Можете ли вы привести пример этой арифметической функции? Вам нужно имя переменной (например, «THIRD») для нее или просто значение индекса?
csny

SUM=$(($6 + $i)); echo $SUM"q;d"Я вижу, что я делаю неправильно.
Джаннис Кристофакис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.