Получение значений из переменных - скрипт bash

Я пытаюсь написать bash-скрипт для вывода значений трех переменных. Продолжайте получать ошибки. Что я делаю не так?

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for i in 1 2 3
do 
echo $(INPUT$i)
done

Когда я запускаю этот скрипт, вывод будет:

syntax error: operand expected (error token is "/tmp/dir1
4
задан 24 January 2014 в 23:57

4 ответа

Bash не поддерживает такой синтаксис напрямую. Вы можете использовать 'eval', однако в современных версиях 'bash' самый простой способ - использовать массив

input=( "/tmp/dir1" "/tmp/dir2" "/tmp/dir3" )

for i in {0,1,2}; do echo "${input[i]}"; done

(обратите внимание, что массивы bash имеют нулевую индексацию); или перечислить все элементы, которые вы можете использовать

for i in "${input[@]}"; do echo "$i"; done
0
ответ дан 24 January 2014 в 23:57

Лучший способ состоит в том, чтобы определить INPUT переменная как массив:

#!/bin/bash

INPUT[1]=/tmp/dir1
INPUT[2]=/tmp/dir2
INPUT[3]=/tmp/dir3

for i in "${INPUT[@]}"
do 
echo $i     #or $INPUT[$i]
done

См. также: http://www.cyberciti.biz/faq/bash-for-loop-array/

0
ответ дан 24 January 2014 в 23:57

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

Вот как вы можете сделать это с помощью eval для доступа к переменным, точно следуя тому, как ОП дал его код:

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for i in {1..3} ; do
    eval "echo \$INPUT$i"
done

Выход:

/tmp/dir1
/tmp/dir2
/tmp/dir3
0
ответ дан 24 January 2014 в 23:57

bash на самом деле поддержки что-то достаточно близкое к тому, что Вы сначала попробовали.

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for s in INPUT{1..3}; do
    echo ${!s}
done

Это работает потому что:

Некоторые протесты (которые также относятся к некоторым из других ответов, которые были отправлены):

  • Если любые значения INPUTn может содержать whitespace1 (как spaces2, вкладки или новые строки) или конструкции со специальными символами, которые были бы расширены (такой как $varname), заключение в кавычки должно использоваться.

    Одинарные кавычки для присвоения являются лучшими, если Вы хотите предотвратить все расширение там:
    INPUT1=/tmp/dir1INPUT1='/tmp/dir with spaces'

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

    Но используйте двойные кавычки, чтобы все еще позволить переменной быть расширенной:
    echo ${!s}echo "${!s}"

    (Это работает, даже если значение после расширения содержит a $. Расширенное содержание не расширено снова.
    Например, BAZ=QUUX FOO='BAR $BAZ'; echo "$FOO" печать BAR $BAZ, нет BAR QUUX.)

  • Если любой из INPUTn мог бы взять значение это echo интерпретировал бы как опция вместо текста, чтобы распечатать, заменить echo с printf '%s\n'.3

    В настоящее время это - сопровождаемый еще одним e, E, или n. Но необходимо, вероятно, рассмотреть что-либо запускающееся с - как опасный в случае, если будущие версии удара добавляют новые опции.


Хотя с точки зрения синтаксиса косвенное расширение, столь же представленное выше, почти так же просто как выполнение его с массивом, все еще можно хотеть использовать массив потому что:

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

Возможно, Вы предназначили /tmp/dir1, /tmp/dir2, и /tmp/dir3 как непрозрачные примеры, которые могут быть заменены чем-либо.

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

input=(/tmp/dir{1..3})

Точно так же, если Ваша цель состоит в том, чтобы только циклично выполниться через /tmp/dir1, /tmp/dir2, и /tmp/dir3 и выполните некоторое действие с каждым, затем Вы не должны хранить их ни в каком виде переменной:

for s in /tmp/dir{1..3}; do
    echo $s
done

Если значения s будет содержать пробельные или специальные символы (см. выше), заключите им в кавычки, но уезжайте {...} диапазон закрыл кавычки путем отдельного заключения в кавычки текста налево и права на него - он не будет расширен, если заключено в кавычки, даже в двойных кавычках.

for s in '/tmp/dir '{1..3}' with  spaces'; do
    echo "$s"
done

Это печатает:

/tmp/dir 1 with  spaces
/tmp/dir 2 with  spaces
/tmp/dir 3 with  spaces

И если Ваша цель состоит в том, чтобы действительно только распечатать /tmp/dir1, /tmp/dir2, и /tmp/dir3, каждый на его собственной строке, затем этот единственный command3 достаточен:

printf '%s\n' /tmp/dir{1..3}

1: Оболочка разделяет текст на слова на пробеле или, если IFS переменная определяется на разделителях полей, которых она указывает. Но Вы обычно не должны волноваться о IFS если Вы не установили его сами.

2: echo hello world на самом деле работает: это печатает hello world, точно так же, как echo 'hello world'. Это вызвано тем, что echo печатает одиночный пробел между каждым отраженным аргументом. Однако echo hello world не эквивалентно echo 'hello world': первый все еще печатает hello world в то время как последняя печать hello world.

3: Для получения дополнительной информации о bash printf встроенный, посмотрите вывод help printf или этот раздел руководства Bash. printf также исполняемый файл, который можно назвать от других оболочек (и в той способности стандартизирован).

0
ответ дан 24 January 2014 в 23:57

Другие вопросы по тегам:

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