Чи можливо надрукувати вміст змісту змінної за допомогою сценарію оболонки? (непряме посилання)


13

Припустимо, я оголосив такі змінні:

$ var='$test'
$ test="my string"

Якщо я друкую їхній вміст, я бачу таке:

$ echo $var
$test

$ echo $test
my string

Я хотів би знайти спосіб друкувати зміст контенту $var(який є вмістом $test). Тому я спробував зробити наступне:

$ echo $(echo $var)
$test

Але тут результат є, $testа не "my string"... Чи можна надрукувати вміст змісту змінних за допомогою bash?


Чи можете ви відредагувати свою публікацію, щоб сказати, яку оболонку ви використовуєте, або які вимоги щодо портативності у вас є?
Майкл Гомер

@MichaelHomer Звичайно, але як саме я можу перевірити цю інформацію?
Рафаель Муйнарськ

Це більше щось, що ви обираєте, ніж щось для перевірки. Наприклад, чи використовуєте ви сценарії з ash, або bash, або csh, або dash, ..., або zsh, або POSIX sh, або вам потрібно працювати в різних системах?
Майкл Гомер

@MichaelHomer Ах, бачу ... я використовую bash. Я просто зміню остаточне запитання і вставляю новий тег потім.
Рафаель Муйнарськ

Відповіді:


21

Ви можете досягти цього, використовуючи непряме розширення змінної bash (до тих пір, поки вам не вдається позбавитись $від вашої базової змінної):

$ var=test
$ test="my string"
$ echo "$var"
test
$ echo "${!var}"
my string

3.5.3 Розширення параметра оболонки


10

У випадку, коли ім'я змінної, що міститься в varпрефіксі, $ви можете використовувати eval:

$ var='$test'
$ test="my string"
$ eval echo $var
my string

Що тут відбувається:

  • bash розширюється $varдо значення $test, виробляючи eval echo $testкоманду;
  • evalоцінює echo $testвираз і дає бажаний результат.

Зауважте, що використання evalв цілому може бути небезпечним (залежно від того, що зберігається var), тому віддайте перевагу уникати цього. Функція непрямого розширення краща для вашого випадку (але вам потрібно позбутися $входу $test).


Звичайно, це помилка. Оригінальна публікація має одинарні цитати. Виправлено.
Даніла Ківер

4
Я завжди рекомендую подвійне цитування посилань на змінну (щоб уникнути неприємностей від несподіваного розбиття слів і розширення підстановки). З eval, вам потрібно два шари подвійних лапках, вирівнюють це: eval echo "\"$var\"". Зауважте, це не означає нічого щодо інших небезпек використання, про evalякі ви згадали.
Гордон Девіссон

9

Схожий на відповідь Jesse_b , але використовуючи змінну опорного імені замість змінної непрямості (потрібно bash4,3+):

$ declare -n var=test
$ test="my string"
$ echo "$var"
my string

Іменна опорна змінна varмістить ім'я змінної, на яку вона посилається. Коли змінна буде відзначена як $var, повертається значення іншої змінної.

bash рекурентно вирішує посилання на імена:

$ declare -n var1=var2
$ declare -n var2=test
$ test="hello world"
$ echo "$var1"
hello world

Для повноти використання асоціативного масиву (в bash4.0+) також є одним із способів вирішення цього питання, залежно від вимог:

$ declare -A strings
$ strings[test]="my string"
$ var=test
$ echo "${strings[$var]}"
my string

Це забезпечує більш гнучкий спосіб доступу до більш ніж одного значення за допомогою ключа або імені, яке може бути визначено динамічно. Це може бути кращим, якщо ви хочете зібрати всі значення певної категорії в одному масиві, але все ж матимете доступ до них за допомогою якогось ключа (наприклад, імена, доступні за ідентифікатором, або імена шляхів, доступні за призначенням тощо), оскільки це не забруднює мінлива область імен сценарію.


3

З zsh:

$ var='$test'
$ test='*'
$ printf '%s\n' ${(e)var}
*

З будь-якою оболонкою Борна

$ eval 'printf "%s\n" "'"$var"'"'
*

Пам’ятайте, що в цих оболонках слід вказати змінні розширення, щоб запобігти спліт + glob ( zshбути винятком) і echoне можна використовувати для довільних даних.

Оскільки з обох (e)і evalє оцінка коду оболонки, важливим є вміст $varперебування під вашим контролем, оскільки в іншому випадку це може бути довільною вразливістю введення команди (те саме, що і ${!var}підходи).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.