динамические переменные в скрипте bash [duplicate]

Этот код суммирует обе переменные! Поместите его в свою функцию

var y = parseInt(document.getElementById("txt1").value);
var z = parseInt(document.getElementById("txt2").value);
var x = (y +z);
document.getElementById("demo").innerHTML = x;`
30
задан Todd A. Jacobs 31 May 2012 в 08:10
поделиться

5 ответов

Вам нужно использовать переменное направление:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
   var="SAMPLE$i"
   echo ${!var}
done

На странице Bash man в разделе «Расширение параметра»:

" Если первый символ параметра является восклицательным знаком (!), Вводится уровень переменной косвенности. Bash использует значение переменной, сформированной из остального параметра, как имя переменной, затем эта переменная расширяется и это значение используется в остальной части подстановки, а не как значение самого параметра. Это называется косвенным расширением.

62
ответ дан Cory Ringdahl 21 August 2018 в 06:23
поделиться
  • 1
    какая оболочка? – mpapis 30 May 2012 в 17:37
  • 2
    Это действительно работает в bash, хорошо! @ johnshen64, откуда вы это узнали? Что называется на странице руководства? – Miquel 30 May 2012 в 17:40
  • 3
    Взгляните на расширение параметров на странице пользователя Bash. Для ${parameter}: «Если первым символом параметра является восклицательный знак (!), Вводится уровень переменной косвенности. Bash использует значение переменной, сформированной из остальной части параметра, как имя переменной; эта переменная затем расширяется и это значение используется в остальной части подстановки, а не значение самого параметра. Это известно как косвенное расширение. & Quot; – dogbane 30 May 2012 в 17:47
  • 4
    Блестящий, спасибо за ссылку. Я бы сказал, что это лучший ответ. – Miquel 30 May 2012 в 17:49
  • 5
    спасибо собаке за подробное объяснение. Очень приятно знать. Я просто использую его и никогда не удосужился узнать, как он называется :-) – johnshen64 30 May 2012 в 18:02

Не является автономным ответом, просто добавлением к ответу Микеля, который я не мог хорошо вписать в комментарий.

Вы можете заполнить массив, используя цикл, оператор + = и документ здесь а также:

SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF

В bash 4.0 это так же просто, как

readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
2
ответ дан chepner 21 August 2018 в 06:23
поделиться

Вы можете использовать eval, как показано ниже:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
  eval echo \$SAMPLE$i
done
3
ответ дан dogbane 21 August 2018 в 06:23
поделиться

Не так далеко, насколько я знаю, сказали они, как сказал @ johnshen64. Кроме того, вы можете решить свою проблему, используя такой массив:

SAMPLE[1]='1-first.with.custom.name'
SAMPLE[2]='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ )) do
    echo ${SAMPLE[$i]}
done

Обратите внимание, что вам не нужно использовать числа, поскольку индексы SAMPLE[hello] будут работать так же хорошо

3
ответ дан Miquel 21 August 2018 в 06:23
поделиться
  • 1
    Хороший момент, но у меня уже была куча SAMPLE # created :) – pQB 30 May 2012 в 17:47
  • 2
    Это не ассоциативный массив, а обычный массив. Ассоциативные массивы используют произвольные строки как индекс. – chepner 30 May 2012 в 17:57
  • 3
    Или вы можете выполнить назначение как это (с нулевым основанием): SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name') или один на основе: SAMPLE=([1]='1-first.with.custom.name' '2-second.with.custom.name'). Если хотите, вы можете разбить задание на несколько строк. – Dennis Williamson 30 May 2012 в 18:55
  • 4
    @chepner, вы правы; исправлено – Miquel 30 May 2012 в 21:32

Проблема

Вы используете значение i , как если бы это был индекс массива. Это не так, потому что SAMPLE1 и SAMPLE2 являются отдельными переменными, а не массивом.

Кроме того, при вызове echo SAMPLE{$i} вы добавляете значение i к слову "ОБРАЗЕЦ." Единственная переменная, которую вы разыгрываете в этом выражении, - $ i, поэтому вы получили результаты, которые вы сделали.

Способы решения проблемы

Существует два основных способа решения этой проблемы :

  1. Многоступенчатое разыменование интерполированной переменной через расширение косвенной переменной eval builtin или .
  2. Итерация по массиву или использование i как индекс в массив.

Разыменование с помощью eval

Самое простое в этом дело ситуация заключается в использовании eval :

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ )); do
    eval echo \$SAMPLE${i}
done

Это добавит значение i в конец переменной и затем обработает результирующую строку , расширяя имя интерполированной переменной (например, SAMPLE1 или SAMPLE2 ).

Разбор с косвенными переменными

Принятый ответ для этого вопрос:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
   var="SAMPLE$i"
   echo ${!var}
done

Это технически трехэтапный процесс. Во-первых, он присваивает имя интерполированной переменной var , затем разделяет имя переменной, хранящуюся в var , и, наконец, расширяет результат. Это выглядит немного чище, и некоторые люди более удобны с этим синтаксисом, чем с eval , но результат в основном тот же.

Итерация по массиву

Вы можете упростить как цикл, так и расширение путем итерации по массиву вместо использования переменной интерполяции. Например:

SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[@]}"; do
    echo "$i"
done

Это добавило преимущества по сравнению с другими методами. В частности:

  1. Вам не нужно указывать сложный цикл теста.
  2. Доступ к отдельным элементам массива осуществляется через синтаксис $ SAMPLE [$ i].
  3. Вы можете получить общее количество элементов с расширением переменной $ {# SAMPLE}.

Практическая эквивалентность для исходного примера

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

16
ответ дан Todd A. Jacobs 21 August 2018 в 06:23
поделиться
  • 1
    -1 для использования eval, где это не нужно. – chepner 30 May 2012 в 17:56
  • 2
    Согласитесь с chepner - это отличный ответ, но пример использования eval должен, если он хранится, иметь предупреждение, чтобы избежать такого использования. Также может быть полезно добавить пример ассоциативных массивов bash 4, если цельность - цель. – Charles Duffy 30 May 2012 в 20:21
  • 3
    Не стесняйтесь указывать, как eval отличается от непрямых переменных для этого случая использования , если вы чувствуете, что сильно об этом. Тем не менее, многие люди избегают eval рефлексивно, даже когда это правильный инструмент для работы, и если вы можете доверять своему исходному источнику, вы можете доверять eval. Добавление отказа от ответственности в каждое сообщение о потенциальных зол eval немного напоминает эти вездесущие ярлыки, говорящие «Предупреждение: этот кофе может быть горячим». – Todd A. Jacobs 30 May 2012 в 20:55
  • 4
    – chepner 30 May 2012 в 22:16
  • 5
    из всех 3 решений, eval - единственный, который работает в золе. +1 для ответа. если бы вы не предполагали использовать команду, никогда ее там не было. – David 21 November 2016 в 11:08
Другие вопросы по тегам:

Похожие вопросы: