2009-11-07 16 views
10

powiedzmy mam nazwa zmiennej jest przechowywany w innej zmiennej:Lookup zmienne powłoki wg nazwy pośrednio

myvar=123 
varname=myvar 

teraz chciałbym dostać 123 tylko przy użyciu zmiennej $ varname. Czy istnieje bezpośredni sposób na to? Nie znalazłem takiego bash wbudowanych dla odnośnika przez nazwę, więc wymyślił to:

function var { v="\$$1"; eval "echo "$v; } 

tak

var $varname # gives 123 

Które nie wygląda tak źle, w końcu, ale zastanawiam się, czy I przegapił coś bardziej oczywistego. Z góry dziękuję!

+0

To jest oznaczony jako duplikat pytania zadanego 6 lat później? Także IMHO to pytanie + odpowiedzi jest bardziej przejrzyste niż te powiązane. – inger

Odpowiedz

12

Z man page of bash:

${!varname} 

Jeżeli pierwszym znakiem parametru jest wykrzyknik, poziom zmiennej zadnie wprowadza. Bash używa wartości zmiennej utworzonej z reszty parametru jako nazwy zmiennej; Ta zmienna jest następnie rozwijana i ta wartość jest używana w pozostałej części zamiast wartości samego parametru. Jest to , znane jako rozszerzenie pośrednie.

+0

Oczywiście, to wszystko. Próbowałem RTFM, ale w jakiś sposób ten opis: ----------------- $ {! Prefix *} $ {! Prefix @} $ {! Prefix @} Nazwy pasujące do prefiksu. Rozwija się do nazw zmiennych, których nazwy zaczynają się od prefiksu, oddzielone pierwszym znakiem specjalnej zmiennej IFS . Gdy użyto @ i rozszerzenie pojawi się w podwójnych cudzysłowach, każda nazwa zmiennej rozszerza się do osobnego słowa. ----------------- nie uznałem za oczywistą odpowiedź. Pozdrawiam za to! – inger

+0

@DigitalRoss: Pytanie zostało oznaczone jako "bash", więc dlaczego chcesz ograniczyć odpowiedź na standard posix? – tangens

+1

To dobra odpowiedź i tak, dotyczy ona basha. Domyślam się, że idealna odpowiedź zapowiedziałaby '$ {! Nazwa_wstawy}', a następnie zanotuj kwestię przenośności, aby uniknąć problemów z OP. – DigitalRoss

12

Nie ma bezpośredniej składni zgodnej z Posix, tylko isma bash.

eval t="\$$varname" 

To będzie działać na każdej powłoki zgodne z POSIX, w tym tych systemów gdzie bash jest powłoka logowania i /bin/sh jest coś mniejsze i szybciej jak ash: Zazwyczaj to zrobić. Lubię bash i używam go dla mojej powłoki logowania, ale unikam bashisms w plikach poleceń.


Uwaga: Jednym z problemów podczas pisania skryptów specyficznych dla basha jest to, że nawet jeśli można liczyć na instalację basha, może to być dowolne miejsce na ścieżce. W takim przypadku dobrym pomysłem może być używanie w pełni ogólnego stylu, ale pamiętaj, że nadal nie jest on w 100% przenośny i ma problemy z bezpieczeństwem.

+0

W zależności od kontekstu, w którym potrzebna jest wartość, można użyć '$ (eval \ $$ nazwa_zmiennej)' zamiast przypisania. –

+0

Próbowałem prawie tego, ale brakowało mi. Krótszy niż moje okrzyki za to! – inger

+0

nie jest '$ (....)' nie-posixem? Czy nie powinno to być '\' eval \ $$ nazwa_zmiennej' \ 'zamiast? –

1

${!varname} powinno wystarczyć

$ var="content" 
$ myvar=var 
$ echo ${!myvar} 
content 
+0

Dzięki, wydaje się, że Twoja odpowiedź dotarła chwilę później niż tangeny, więc ją wybrałem :) – inger

1

zwykle spojrzeć na Advance Bash-Scripting Guide kiedy muszę odświeżyć swoje umiejętności bash.

chodzi o wygląd pytanie na Indirect References

notację:

Version < 2 
\$$var 

Version >= 2 
${!varname} 
+0

Hmm, szybko przejrzałem ten przewodnik - najwyraźniej zbyt szybko :) Wygląda na to, że muszę to dobrze przeczytać .. dzięki za wskazówkę ! – inger

+0

To jest moje szybkie odniesienie z wyboru, staram się go używać częściej niż strony man. Ale jak mówisz, szybkie spojrzenie czasami nie wystarcza. –

+0

Ogólnie rzecz biorąc, ABS powinien być przyjmowany z wielkim ziarnem soli. Jednak nic złego w tej odpowiedzi jako takiej. – tripleee

0
# bmuSetIndirectVar() 
# TO DOUBLE CHECK THIS COMMENT AND DEMO 
# This function is an helper to read indirect variables. 
# i.e. get the content of a variable whose name is saved 
# within an other variable. Like: 
# MYDIR="/tmp" 
# WHICHDIR="MYDIR" 
#  bmuSetIndirectVar "WHICHDIR" "$MYDIR" 
# 
bmuSetIndirectVar(){ 
    tmpVarName=$1 
    locVarName=$1 
    extVarName=$2 
    #echo "debug Ind Input >$1< >$2<" 
    eval tmpVarName=\$$extVarName 
    #echo "debug Ind Output >$tmpVarName< >$extVarName<" 
    export $locVarName="${tmpVarName}" 
} 

Obecnie używam tego małego funkcję. Nie jestem w pełni z niego zadowolony i widziałem różne rozwiązania w Internecie (gdybym mógł sobie przypomnieć, bym je tutaj napisał), ale wydaje się, że działa. W tych kilku liniach jest już trochę nadmiarowości i dodatkowych danych, ale było to pomocne przy debugowaniu.

Jeśli chcesz zobaczyć go w miejscu, czyli tam gdzie używam go sprawdzić: https://github.com/mariotti/bmu/blob/master/bin/backmeup.shellfunctions.sh

Oczywiście nie jest to najlepsze rozwiązanie, ale sprawił, że dzieje się z pracy, w nadziei Mogę zastąpić to czymś nieco bardziej ogólnym wkrótce.

+0

Przed pytaniami;) To co nie podoba mi się w tej funkcji to to, że używam "ewaluacji", która zazwyczaj jest wyzwaniem dla złego projektu. Oczywiście są miejsca, w których jest to potrzebne. Podoba mi się to, że używając funkcji mogę odłączyć kod od problemu i zoptymalizować go później. Może nawet wprowadzić kontrolę wersji powłoki lub coś podobnego. – mariotti