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 ))
giannis christofakis

Відповіді:


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}"?
giannis christofakis

1
Його називають непрямим розширенням розширення bashпараметрів ...
читайте про

1
Bash також має більш хорошу альтернативу declare/ eval: printf -v varname '%fmt' args. Деякі внутрішні функції базового завершення використовують це для дзвінка за посиланням. (передайте ім'я змінної, яку потрібно зберегти).
Пітер Кордес

Примітка. Використання declareлише встановлює змінну в локальній області, тоді як evalпідхід встановлює її в глобальному масштабі.
користувач

11

Якщо ви хочете посилатися на змінну bash, зберігаючи ім’я в іншій змінній, ви можете зробити це наступним чином:

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

Ви зберігаєте ім'я змінної, до якої ви хочете отримати доступ, скажімо, у цьому випадку var2. Потім ви отримуєте доступ до нього, ${!<varable name>}де <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

Що я отримую від вашого коду та вашого бажаного виводу (виправте мене, якщо я помиляюся):
Не використовуються назви змінних "ПЕРШИЙ" / "ДРУГИЙ" / ..., вам просто потрібна петля з індексом. .

Це зробить роботу:

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


Так, ви праві, за винятком того, що я хочу виконати арифметичну функцію зі змінною.
giannis christofakis

Чи можете ви навести приклад цієї арифметичної функції? Вам потрібна назва змінної (наприклад, "THIRD") для неї або просто значення індексу?
csny

SUM=$(($6 + $i)); echo $SUM"q;d", Я бачу, що я робив не так.
giannis christofakis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.