Використовуйте посилання змінної "всередині" іншої змінної


27

Я впевнений, що це досить просто, я просто не знаю, як це зробити.

#!/usr/bin/ksh
set `iostat`
myvar=6

Я хочу, щоб щось таке, echo ${$myvar}що я хочу інтерпретувати як ${$myvar}-> ${6}->value


4
Технічний термін є змінною непрямою .
Тор

Відповіді:


29

Це можна зробити за допомогою evalвбудованої в багато тонких оболонок, включаючи ksh:

#!/usr/bin/ksh
set $(iostat)
myvar=6
eval "echo \${$myvar}"

Хитрість полягає в тому, щоб подвоїти котирування рядка, на який ви evalподаєте, так, щоб $ myvar замінився на "6", і зворотній косий ривок зовнішнього знака долара, щоб evalотримати рядок "6 доларів".

Я отримав "% user" для виводу, але я спробував це на багатопроцесорній машині RHEL.


4
Ви офіційно - Верховний Великий Великий Майстер тижня, який працює навіть над надзвичайно жахливим ksh (дійсно pdksh) у OpenBSD 5.4. Якщо ви хочете встановити var vv значенням var, ім'я якого у var vn , просто зробіть vv=$( eval "echo \$$vn" ). Дякую тонну!
execNext

25

Непряма посилання на змінну

Сучасні розширені оболонки мають метод посилання на значення змінної, ім'я якої зберігається в іншій змінній. На жаль, метод відрізняється між ksh, bash та zsh.

У mksh ≥R39b ви можете зробити myvarnameref:

typeset -n myvar=6
echo "$myvar"

Це не працює в ATT ksh93, оскільки він не підтримує namerefs до позиційних параметрів. У випадку, коли у вас є змінна, що містить ім'я змінної, ви можете використовувати цей метод.

foo=bar
typeset -n myvar=foo
echo "$myvar"  # prints bar

В bash ≥2.0 ви можете писати

echo "${!myvar}"

В zsh можна писати

echo ${(P)myvar}

У старих оболонках, включаючи ksh88 і pdksh, ваш єдиний спосіб звернення, коли у вас є змінна, що містить інше ім'я змінної і хочете використовувати значення цієї змінної eval, як пояснив Брюс Едігер . Це рішення працює в будь-якій оболонці Bourne / POSIX.

eval "value=\${$myvar}"
echo "$value"

Використання масиву

Тут найкращий метод: він простіший і портативніший.

Для вашого випадку використання, у будь-якій оболонці з масивами (всі ksh варіанти, bash ≥2.0, zsh), ви можете призначити змінну масиву та взяти бажаний елемент. Остерігайтеся, щоб масиви ksh та bash починалися з нумерації з 0, але zsh починається з 1, якщо ви не видаєте setopt ksh_arraysабо emulate ksh.

set -A iostat -- $(iostat)
echo "${iostat[5]}"

Якщо ви хочете скопіювати позиційні параметри в змінну масиву a:

set -A a -- "$@"

У ksh93, mksh ≥R39b, bash ≥2.0 та zsh, ви можете використовувати синтаксис присвоєння масиву:

iostat=($(iostat))
echo "${iostat[5]}"

Нічого так, ваше рішення "Bourne / POSIX" також працює у ksh / pdksh OpenBSD 5.4. Щоб застосувати його до прикладу у своєму коментарі до відповіді Брюса Едігера вище, просто зробіть eval "vv=\${$vn}". Merci beaupoup, добрий сер.
execNext

1

Як вказував Жилл (який надав bashчастину відповіді), що також не визнає недійсним Брюса Едігера (про те, як це зробити портативно eval), ось як це зробити namerefостаннім часом mksh(і AT&T ksh93, за винятком - як @Gilles прокоментував - namerefs не може посилатися на позиційні параметри в AT&T ksh, лише до названих параметрів):

#!/bin/mksh
set -- $(iostat)
nameref myvar=6
echo $myvar

Додано --після setдля покращеної стійкості.


Станом на ksh 93u, namerefs не можуть посилатися на позиційні параметри ( typeset: 6: invalid variable name).
Жил "ТАК - перестань бути злим"

0

Ще одне використання масивів

Якийсь час не використовував ні ksh, ні будь-який варіант, тому я не впевнений, чи ksh (або bash) має подібні можливості. Моя основна оболонка - zsh. Я використовую масиви при обробці результатів з таких команд, як iostat, оскільки вони створюють кілька рядків, і не всі рядки мають однаковий формат / довжину.

#! /bin/zsh
IOStatOutput=("${(@f)$(iostat)}") # Produces one element per line

Сказане також обходить використання позиційних параметрів. Тепер, якщо ви хочете генерувати, скажімо, масив пристроїв:

for Element in {7..${#IOStatOutput}} # Devices listed in elements 7 thru the last
do
    DevList+=( ${${=IOStatOutput[Element]}[1]} )
done

Я знаходжу більш дрібні шматки набагато простішими в обробці. Можливо, вам не знадобиться використовувати непрямі посилання на змінну залежно від вашого коду. Знати, як це працює, все-таки добре знати. Я цим самим користуюся.

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