Co mówi tytuł: co to znaczy ująć zmienną w {}
, ""
lub "{}
„? Nie udało mi się znaleźć żadnych wyjaśnień na ten temat w Internecie - nie mogłem się do nich odnieść poza użyciem symboli, nic nie daje.
Oto przykład:
declare -a groups
groups+=("CN=exampleexample,OU=exampleexample,OU=exampleexample,DC=example,DC=com")
groups+=("CN=example example,OU=example example,OU=example example,DC=example,DC=com")
To:
for group in "${groups[@]}"; do
echo $group
done
Okazuje się, że różni się znacznie od tego:
for group in $groups; do
echo $group
done
i to:
for group in ${groups}; do
echo $group
done
Tylko pierwszy z nich spełnia to, czego chcę: iteruje przez każdy element tablicy. Nie jestem do końca jasne, na różnice między $groups
, "$groups"
, ${groups}
i "${groups}"
. Gdyby ktoś mógł to wyjaśnić, byłbym wdzięczny.
Jako dodatkowe pytanie - czy ktoś zna akceptowany sposób odwoływania się do tych enkapsulacji?
bash
skrypcie?Odpowiedzi:
Szelki (
$var
vs.${var}
)W większości przypadków
$var
i${var}
są takie same:var=foo echo $var # foo echo ${var} # foo
Nawiasy klamrowe są potrzebne tylko do rozwiązania niejednoznaczności w wyrażeniach:
var=foo echo $varbar # Prints nothing because there is no variable 'varbar' echo ${var}bar # foobar
Cytaty (
$var
porównaniu"$var"
vs."${var}"
)Kiedy dodajesz podwójne cudzysłowy wokół zmiennej, mówisz powłoce, aby traktowała ją jako pojedyncze słowo, nawet jeśli zawiera spacje:
var="foo bar" for i in "$var"; do # Expands to 'for i in "foo bar"; do...' echo $i # so only runs the loop once done # foo bar
Porównaj to zachowanie z następującymi:
var="foo bar" for i in $var; do # Expands to 'for i in foo bar; do...' echo $i # so runs the loop twice, once for each argument done # foo # bar
Podobnie jak w przypadku
$var
vs.${var}
, szelki są potrzebne tylko do ujednoznacznienia, na przykład:var="foo bar" for i in "$varbar"; do # Expands to 'for i in ""; do...' since there is no echo $i # variable named 'varbar', so loop runs once and done # prints nothing (actually "") var="foo bar" for i in "${var}bar"; do # Expands to 'for i in "foo barbar"; do...' echo $i # so runs the loop once done # foo barbar
Zwróć uwagę, że
"${var}bar"
w drugim przykładzie powyżej można również zapisać"${var}"bar
, w którym to przypadku nie potrzebujesz już nawiasów klamrowych, tj"$var"bar
. Jeśli jednak masz dużo cudzysłowów w swoim ciągu, te alternatywne formy mogą być trudne do odczytania (a zatem trudne w utrzymaniu). Ta strona stanowi dobre wprowadzenie do cytowania w Bash.Tablicami (
$var
porównaniu$var[@]
vs.${var[@]}
)Teraz twoja tablica. Zgodnie z instrukcją bash :
Innymi słowy, jeśli nie podasz indeksu
[]
, otrzymasz pierwszy element tablicy:foo=(a b c) echo $foo # a
Co jest dokładnie tym samym, co
foo=(a b c) echo ${foo} # a
Aby pobrać wszystkie elementy tablicy,
@
jako indeksu należy użyć np${foo[@]}
. Nawiasy klamrowe są wymagane przy tablicach, ponieważ bez nich powłoka najpierw rozszerzyłaby$foo
część, podając pierwszy element tablicy, a po nim literał[@]
:foo=(a b c) echo ${foo[@]} # a b c echo $foo[@] # a[@]
Ta strona jest dobrym wprowadzeniem do tablic w Bash.
Cytaty ponownie odwiedzone (
${foo[@]}
vs."${foo[@]}"
)Nie pytałeś o to, ale jest to subtelna różnica, o której warto wiedzieć. Jeśli elementy Twojej tablicy mogą zawierać spacje, musisz użyć podwójnych cudzysłowów, aby każdy element był traktowany jako osobne „słowo:”
foo=("the first" "the second") for i in "${foo[@]}"; do # Expands to 'for i in "the first" "the second"; do...' echo $i # so the loop runs twice done # the first # the second
Porównaj to z zachowaniem bez podwójnych cudzysłowów:
foo=("the first" "the second") for i in ${foo[@]}; do # Expands to 'for i in the first the second; do...' echo $i # so the loop runs four times! done # the # first # the # second
źródło
${var:?}
:, który spowoduje błąd, gdy zmienna nie jest ustawiona lub nie jest ustawiona. REF: github.com/koalaman/shellcheck/wiki/SC2154${parameter:-word}
,${parameter:=word}
,${parameter#word}
,${parameter/pattern/string}
, i tak dalej. Myślę, że to wykracza poza zakres tej odpowiedzi.TL; DR
Wszystkie podane przykłady są odmianami rozszerzeń powłoki Bash . Rozszerzenia następują w określonej kolejności, a niektóre mają określone przypadki użycia.
Nawiasy klamrowe jako ograniczniki znaczników
${var}
Składnia służy przede wszystkim do wyznaczania niejednoznaczne tokenów. Na przykład rozważ następujące kwestie:$ var1=foo; var2=bar; var12=12 $ echo $var12 12 $ echo ${var1}2 foo2
Nawiasy klamrowe w rozszerzeniach tablic
Nawiasy są wymagane, aby uzyskać dostęp do elementów tablicy i innych specjalnych rozszerzeń . Na przykład:
$ foo=(1 2 3) # Returns first element only. $ echo $foo 1 # Returns all array elements. $ echo ${foo[*]} 1 2 3 # Returns number of elements in array. $ echo ${#foo[*]} 3
Tokenizacja
Większość pozostałych pytań dotyczy cytowania i sposobu, w jaki powłoka tokenizuje dane wejściowe. Rozważ różnicę w sposobie, w jaki powłoka dokonuje podziału na słowa w następujących przykładach:
$ var1=foo; var2=bar; count_params () { echo $#; } # Variables are interpolated into a single string. $ count_params "$var1 $var2" 1 # Each variable is quoted separately, created two arguments. $ count_params "$var1" "$var2" 2
@Symbolu współdziała z podaniem inaczej niż *. Konkretnie:
$@
„[e] rozwija się do parametrów pozycyjnych, zaczynając od jedynki. Kiedy interpretacja następuje w cudzysłowach, każdy parametr jest interpretowany jako osobne słowo”.${name[*]}
rozwija się do pojedynczego słowa z wartością każdego elementu tablicy oddzieloną pierwszym znakiem zmiennej IFS i${name[@]}
rozwija każdy element nazwy do osobnego słowa”.Możesz to zobaczyć w akcji w następujący sposób:
$ count_params () { echo $#; } $ set -- foo bar baz $ count_params "$@" 3 $ count_params "$*" 1
Użycie rozwinięcia w cudzysłowie ma ogromne znaczenie, gdy zmienne odnoszą się do wartości ze spacjami lub znakami specjalnymi, które mogą uniemożliwić powłoce podział na słowa w zamierzony sposób. Zobacz Cytowanie, aby uzyskać więcej informacji na temat cytowania w Bash.
źródło
Musisz odróżnić tablice od prostych zmiennych - a Twój przykład używa tablicy.
Dla zwykłych zmiennych:
$var
i${var}
są dokładnie równoważne."$var"
i"${var}"
są dokładnie równoważne.Jednak te dwie pary nie są w 100% identyczne we wszystkich przypadkach. Rozważ poniższe dane wyjściowe:
$ var=" abc def " $ printf "X%sX\n" $var XabcX XdefX $ printf "X%sX\n" "${var}" X abc def X $
Bez podwójnych cudzysłowów wokół zmiennej wewnętrzny odstęp jest tracony, a interpretacja jest traktowana jako dwa argumenty
printf
polecenia. W przypadku podwójnych cudzysłowów wokół zmiennej zachowywany jest wewnętrzny odstęp, a interpretacja jest traktowana jako jeden argumentprintf
polecenia.W przypadku tablic reguły są podobne i różne.
groups
jest tablicą, odwołuje się$groups
lub${groups}
jest równoznaczne z odwołaniem${groups[0]}
, zerowy element tablicy."${groups[@]}"
jest analogiczne do odniesienia"$@"
; zachowuje odstępy w poszczególnych elementach tablicy i zwraca listę wartości, po jednej wartości na element tablicy.${groups[@]}
bez podwójnych cudzysłowów nie zachowują odstępów i mogą wprowadzić więcej wartości niż elementów tablicy, jeśli niektóre elementy zawierają spacje.Na przykład:
$ groups=("abc def" " pqr xyz ") $ printf "X%sX\n" ${groups[@]} XabcX XdefX XpqrX XxyzX $ printf "X%sX\n" "${groups[@]}" Xabc defX X pqr xyz X $ printf "X%sX\n" $groups XabcX XdefX $ printf "X%sX\n" "$groups" Xabc defX $
Używanie
*
zamiast@
prowadzi do nieznacznie różnych wyników.Zobacz także Jak iterować po argumentach w
bash
skrypcie .źródło
Drugie zdanie pierwszego akapitu w sekcji Rozwijanie parametrów w
man bash
mówi:Co mówi, że nazwa to po prostu nawiasy klamrowe , a głównym celem jest wyjaśnienie, gdzie zaczyna się i kończy:
foo='bar' echo "$foobar" # nothing echo "${foo}bar" barbar
Jeśli będziesz czytać dalej, odkryjesz,
Przetestujmy:
$ set -- {0..100} $ echo $22 12 $ echo ${22} 20
Huh. Schludny. Szczerze mówiąc, nie wiedziałem tego przed napisaniem tego (nigdy wcześniej nie miałem więcej niż 9 parametrów pozycyjnych).
Oczywiście nawiasy klamrowe są również potrzebne do wykonywania zaawansowanych funkcji rozszerzania parametrów, takich jak
${parameter:-word} ${parameter:=word} ${parameter:?word} … [read the section for more]
a także rozszerzanie macierzy.
źródło
Powiązany przypadek nie omówiony powyżej. Cytowanie pustej zmiennej wydaje się zmieniać rzeczy
test -n
. Jest to konkretnie podane jako przykład winfo
tekściecoreutils
, ale nie do końca wyjaśnione:16.3.4 String tests ------------------- These options test string characteristics. You may need to quote STRING arguments for the shell. For example: test -n "$V" The quotes here prevent the wrong arguments from being passed to `test' if `$V' is empty or contains special characters.
Bardzo chciałbym usłyszeć szczegółowe wyjaśnienie. Moje testy to potwierdzają i teraz cytuję moje zmienne dla wszystkich testów łańcuchowych, aby uniknąć
-z
i-n
zwrócić ten sam wynik.$ unset a $ if [ -z $a ]; then echo unset; else echo set; fi unset $ if [ -n $a ]; then echo set; else echo unset; fi set # highly unexpected! $ unset a $ if [ -z "$a" ]; then echo unset; else echo set; fi unset $ if [ -n "$a" ]; then echo set; else echo unset; fi unset # much better
źródło
Cóż, wiem, że hermetyzacja zmiennej pomaga w pracy z czymś takim:
${groups%example}
lub taką składnię, gdzie chcesz coś zrobić ze swoją zmienną przed zwróceniem wartości.
Teraz, jeśli widzisz swój kod, cała magia jest w środku
${groups[@]}
magia jest w tym, ponieważ nie możesz po prostu napisać:
$groups[@]
Umieszczasz swoją zmienną wewnątrz,
{}
ponieważ chcesz używać znaków specjalnych[]
i@
. Nie możesz nazwać ani wywołać swojej zmiennej tylko:@
lubsomething[]
dlatego, że są to znaki zastrzeżone dla innych operacji i nazw.źródło