Najpierw oddziel zsh od reszty. To nie jest kwestia starych czy współczesnych powłok: zsh zachowuje się inaczej. Projektanci zsh postanowili uczynić go niezgodnym z tradycyjnymi powłokami (Bourne, ksh, bash), ale łatwiejszym w użyciu.
Po drugie, o wiele łatwiej jest używać podwójnych cudzysłowów przez cały czas niż pamiętać, kiedy są potrzebne. Są one potrzebne przez większość czasu, więc musisz się uczyć, kiedy nie są potrzebne, a nie kiedy są potrzebne.
W skrócie, podwójne cudzysłowy są konieczne wszędzie tam, gdzie oczekiwana jest lista słów lub wzór . Są opcjonalne w kontekstach, w których analizator oczekuje surowego ciągu.
Co dzieje się bez cytatów
Zauważ, że bez podwójnych cudzysłowów zdarzają się dwie rzeczy.
- Po pierwsze, wynik interpretacji (wartość zmiennej dla podstawienia parametru jak
${foo}
lub wynik polecenia dla podstawienia polecenia jak $(foo)
) jest dzielony na słowa wszędzie tam, gdzie zawiera białe znaki.
Dokładniej, wynik rozwinięcia jest dzielony na każdy znak, który pojawia się w wartości IFS
zmiennej (znak separatora). Jeśli sekwencja znaków separatora zawiera spacje (spację, tabulator lub znak nowej linii), spacja jest liczona jako pojedynczy znak; wiodące, końcowe lub powtarzające się separatory niebiałe prowadzą do pustych pól. Na przykład, with IFS=" :"
, :one::two : three: :four
produkuje puste pola przed one
, pomiędzy one
i two
oraz (jeden) pomiędzy three
i four
.
- Każde pole powstałe w wyniku podziału jest interpretowane jako glob (wzór wieloznaczny), jeśli zawiera jeden ze znaków
\[*?
. Jeśli ten wzór pasuje do jednej lub więcej nazw plików, wzór jest zastępowany listą pasujących nazw plików.
Niecytowane rozwinięcie zmiennej $foo
jest potocznie nazywane „operatorem podziału + operatora globalnego”, w przeciwieństwie do tego, "$foo"
który po prostu przyjmuje wartość zmiennej foo
. To samo dotyczy podstawiania poleceń: "$(foo)"
to podstawienie polecenia, $(foo)
to zastąpienie polecenia, po którym następuje split + glob.
Gdzie można pominąć podwójne cudzysłowy
Oto wszystkie przypadki, o których mogę myśleć w powłoce w stylu Bourne'a, w której można wpisać zmienną lub podstawienie polecenia bez podwójnych cudzysłowów, a wartość jest interpretowana dosłownie.
Po prawej stronie zadania.
var=$stuff
a_single_star=*
Zauważ, że potrzebujesz podwójnych cudzysłowów po export
, ponieważ jest to zwykłe wbudowane, a nie słowo kluczowe. Jest to prawdą tylko w niektórych powłokach, takich jak dash, zsh (w emulacji sh), yash lub posh; bash i ksh traktują export
specjalnie.
export VAR="$stuff"
W case
oświadczeniu.
case $var in …
Zauważ, że potrzebujesz podwójnych cudzysłowów we wzorze przypadku. Podział słów nie występuje we wzorcu wielkości liter, ale zmienna niecytowana jest interpretowana jako wzorzec, podczas gdy zmienna cytowana jest interpretowana jako ciąg literału.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
W podwójnych nawiasach. Podwójne nawiasy kwadratowe są specjalną składnią powłoki.
[[ -e $filename ]]
Tyle, że potrzebujesz podwójnych cudzysłowów tam, gdzie oczekuje się wzorca lub wyrażenia regularnego: po prawej stronie =
lub ==
lub !=
lub =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
Potrzebujesz podwójnych cudzysłowów jak zwykle w pojedynczych nawiasach, [ … ]
ponieważ są one zwykłą składnią powłoki (jest to polecenie, które się wywołuje [
). Zobacz nawiasy pojedyncze lub podwójne
W przekierowaniu w nieinteraktywnych powłokach POSIX (nie bash
, ani ksh88
).
echo "hello world" >$filename
Niektóre powłoki, gdy są interaktywne, traktują wartość zmiennej jako wzór wieloznaczny. POSIX zabrania tego zachowania w nieinteraktywnych powłokach, ale kilka powłok, w tym bash (z wyjątkiem trybu POSIX) i ksh88 (w tym gdy jest to (rzekomo) POSIX sh
niektórych komercyjnych uniksów takich jak Solaris) nadal to bash
robi ( próbuje również podzielić i przekierowanie nie powiedzie się, chyba że rozłam + nazw plików wyników dokładnie jednego słowa), dlatego lepiej zacytować cele przekierowań w sh
skrypcie w przypadku, gdy chcesz przekonwertować go do bash
skryptu niektóre dni, lub uruchomić go w systemie, w którym sh
jest niezgodny w tym punkcie lub może pochodzić z interaktywnych powłok.
Wewnątrz wyrażenia arytmetycznego. W rzeczywistości musisz pominąć cudzysłowy, aby zmienna była analizowana jako wyrażenie arytmetyczne.
expr=2*2
echo "$(($expr))"
Jednak potrzebujesz cudzysłowów wokół rozszerzenia arytmetycznego, ponieważ są one podzielone na słowa w większości powłok, jak wymaga POSIX (!?).
W indeksie tablicy asocjacyjnej.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
W niektórych rzadkich przypadkach przydatna może być niecytowana zmienna i podstawienie polecenia:
- Gdy wartość zmiennej lub wynik polecenia składa się z listy wzorców globu, a chcesz rozwinąć te wzorce do listy pasujących plików.
- Jeśli wiesz, że wartość nie zawiera znaku wieloznacznego,
$IFS
nie została ona zmodyfikowana i chcesz podzielić ją na białe znaki.
- Jeśli chcesz podzielić wartość na określony znak: wyłącz globowanie za pomocą
set -f
, ustaw IFS
znak separatora (lub zostaw to w spokoju, aby dzielił się spacją), a następnie wykonaj rozwinięcie.
Zsh
W Zsh można przeoczyć podwójne cudzysłowy przez większość czasu, z kilkoma wyjątkami.
$var
nigdy nie rozwija się do wielu słów, jednak rozwija się do pustej listy (w przeciwieństwie do listy zawierającej pojedyncze, puste słowo), jeśli wartością var
jest pusty ciąg. Kontrast:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
Podobnie "${array[@]}"
rozwija się do wszystkich elementów tablicy, natomiast $array
rozwija się tylko do niepustych elementów.
@
Flag ekspansja parametr czasami wymaga cudzysłowie całej substytucji: "${(@)foo}"
.
Podstawienie polecenia podlega podziałowi pola, jeśli nie jest cytowane: echo $(echo 'a'; echo '*')
drukuje a *
(z pojedynczą spacją), podczas gdy echo "$(echo 'a'; echo '*')"
drukuje niezmodyfikowany ciąg dwuwierszowy. Użyj, "$(somecommand)"
aby uzyskać wynik polecenia w jednym słowie, bez ostatnich znaków nowej linii. Użyj, "${$(somecommand; echo _)%?}"
aby uzyskać dokładny wynik polecenia, w tym końcowe znaki nowej linii. Użyj, "${(@f)$(somecommand)}"
aby uzyskać tablicę wierszy z danych wyjściowych polecenia.
SH_WORD_SPLIT
opcji.