Stará rada bývala uvozovat jakýkoli výraz obsahující $VARIABLE
, alespoň pokud bychom chtěli, aby to bylo interpretováno shellem jako jedna jediná položka, jinak jakékoli mezery v obsahu $VARIABLE
by shodil skořápku.
Chápu však, že v novějších verzích shellů již není dvojité uvozování vždy potřeba (alespoň pro výše popsaný účel). Například v bash
:
% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory
V zsh
, na druhou stranu, stejné tři příkazy uspějí. Na základě tohoto experimentu se tedy zdá, že v bash
, lze vynechat dvojité uvozovky uvnitř [[ ... ]]
, ale ne uvnitř [ ... ]
ani v argumentech příkazového řádku, zatímco v zsh
, mohou být dvojité uvozovky ve všech těchto případech vynechány.
Ale odvodit obecná pravidla z neoficiálních příkladů, jako je ten výše, je náhodný návrh. Bylo by hezké vidět souhrn toho, kdy je nutné dvojité uvozování. Primárně mě zajímá zsh
, bash
a /bin/sh
.
Přijatá odpověď:
Nejprve oddělte zsh od zbytku. Není to záležitost starých a moderních shellů:zsh se chová jinak. Návrháři zsh se rozhodli, že je nekompatibilní s tradičními shelly (Bourne, ksh, bash), ale snáze se používá.
Za druhé, je mnohem jednodušší používat dvojité uvozovky neustále, než si pamatovat, kdy jsou potřeba. Jsou potřeba většinu času, takže se budete muset učit, když nejsou potřeba, ne když jsou potřeba.
Stručně řečeno, dvojité uvozovky jsou nutné všude tam, kde se očekává seznam slov nebo vzor . Jsou volitelné v kontextech, kde analyzátor očekává nezpracovaný řetězec.
Co se stane bez uvozovek
Všimněte si, že bez dvojitých uvozovek se stanou dvě věci.
- Zaprvé výsledek expanze (hodnota proměnné pro substituci parametru jako
${foo}
, nebo výstup příkazu pro náhradu příkazu jako$(foo)
) se rozdělí na slova všude tam, kde obsahuje mezery.
Přesněji řečeno, výsledek rozbalení je rozdělen na každý znak, který se objeví v hodnotěIFS
proměnná (znak oddělovače). Pokud sekvence oddělovacích znaků obsahuje mezery (mezera, tabulátor nebo nový řádek), mezery se počítají jako jeden znak; úvodní, koncové nebo opakované oddělovače bez mezer vedou k prázdným polím. Například pomocíIFS=" :"
,:one::two : three: :four
vytváří prázdná pole předone
, mezione
atwo
, a (jeden) mezithree
afour
. - Každé pole, které je výsledkem rozdělení, je interpretováno jako globus (zástupný znak), pokud obsahuje jeden ze znaků
[*?
. Pokud se tento vzor shoduje s jedním nebo více názvy souborů, bude vzor nahrazen seznamem odpovídajících názvů souborů.
Nekótovaná expanze proměnné $foo
je hovorově známý jako "operátor split+glob", na rozdíl od "$foo"
která pouze přebírá hodnotu proměnné foo
. Totéž platí pro substituci příkazů:"$(foo)"
je náhrada příkazu, $(foo)
je substituce příkazu následovaná split+glob.
Kde můžete vynechat dvojité uvozovky
Zde jsou všechny případy, které mě napadají v shellu ve stylu Bourne, kde můžete napsat substituci proměnné nebo příkazu bez uvozovek a hodnota je interpretována doslovně.
-
Na pravé straně úkolu.
var=$stuff a_single_star=*
Všimněte si, že za
export
potřebujete dvojité uvozovky , protože je to obyčejná vestavěná funkce, nikoli klíčové slovo. To platí pouze pro některé shelly, jako je pomlčka, zsh (v emulaci sh), yash nebo posh; bash i ksh zacházejí sexport
speciálně.export VAR="$stuff"
-
V
case
prohlášení.case $var in …
Všimněte si, že potřebujete dvojité uvozovky ve vzoru velkých a malých písmen. K dělení slov nedochází ve vzoru velkých a malých písmen, ale proměnná bez uvozovek je interpretována jako vzor, zatímco proměnná v uvozovkách je interpretována jako doslovný řetězec.
a_star='a*' case $var in "$a_star") echo "'$var' is the two characters a, *";; $a_star) echo "'$var' begins with a";; esac
-
Ve dvojitých závorkách. Dvojité závorky jsou speciální syntaxí shellu.
[[ -e $filename ]]
Kromě toho, že potřebujete dvojité uvozovky tam, kde se očekává vzor nebo regulární výraz:na pravé straně
=
nebo==
nebo!=
nebo=~
.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
Potřebujete dvojité uvozovky jako obvykle v jednoduchých závorkách
[ … ]
protože jde o běžnou syntaxi shellu (je to příkaz, který se náhodou nazývá[
). Viz Jednoduché nebo dvojité závorky -
V přesměrování v neinteraktivních shellech POSIX (nikoli
bash
, aniksh88
).echo "hello world" >$filename
Některé shelly, když jsou interaktivní, zacházejí s hodnotou proměnné jako se zástupným vzorem. POSIX zakazuje toto chování v neinteraktivních shellech, ale několik shellů včetně bash (kromě režimu POSIX) a ksh88 (včetně případů, kdy je nalezen jako (údajně) POSIX
sh
některých komerčních Unices jako Solaris) to tam stále dělá (bash
se také pokouší o rozdělení a přesměrování se nezdaří, pokud rozdělení+globování výsledkem je přesně jedno slovo), proto je lepší uvádět cíle přesměrování vsh
skript pro případ, že jej chcete převést nabash
skript jednoho dne, nebo jej spusťte na systému, kde jesh
v tomto bodě nevyhovuje, nebo může pocházet z zdrojů z interaktivních shellů. -
Uvnitř aritmetického výrazu. Ve skutečnosti musíte uvozovky vynechat, aby mohla být proměnná analyzována jako aritmetický výraz.
expr=2*2 echo "$(($expr))"
Potřebujete však uvozovky kolem aritmetického rozšíření, protože ve většině shellů podléhají dělení slov, jak vyžaduje POSIX (!?).
-
V dolním indexu asociativního pole.
typeset -A a i='foo bar*qux' a[foo bar*qux]=hello echo "${a[$i]}"
V některých vzácných případech může být užitečná proměnná a příkazy bez uvozovek:
- Pokud se hodnota proměnné nebo výstup příkazu skládá ze seznamu vzorů glob a chcete tyto vzory rozšířit na seznam odpovídajících souborů.
- Když víte, že hodnota neobsahuje žádný zástupný znak,
$IFS
nebyl změněn a chcete jej rozdělit na mezery. - Chcete-li rozdělit hodnotu na určitý znak:vypněte globování pomocí
set -f
, nastavteIFS
na oddělovací znak (nebo jej ponechte tak, aby se rozdělil na mezery), pak proveďte rozšíření.
Zsh
V zsh můžete většinou až na pár výjimek vynechat dvojité uvozovky.
-
$var
nikdy se nerozšíří na více slov, ale rozšíří se na prázdný seznam (na rozdíl od seznamu obsahujícího jediné prázdné slovo), pokud je hodnotavar
je prázdný řetězec. Kontrast:var= print -l $var foo # prints just foo print -l "$var" foo # prints an empty line, then foo
Podobně
"${array[@]}"
expanduje na všechny prvky pole, zatímco$array
expanduje pouze na neprázdné prvky. -
@
příznak rozšíření parametru někdy vyžaduje uvozovky kolem celé náhrady:"${(@)foo}"
. -
Náhrada příkazu podstoupí rozdělení pole, pokud není uvedeno v uvozovkách:
echo $(echo 'a'; echo '*')
vypíšea *
(s jednou mezerou) zatímcoecho "$(echo 'a'; echo '*')"
vytiskne neupravený dvouřádkový řetězec. Použijte"$(somecommand)"
Chcete-li získat výstup příkazu v jediném slově, bez posledních řádků. Použijte"${$(somecommand; echo _)%?}"
získat přesný výstup příkazu včetně posledních řádků. Použijte"${(@f)$(somecommand)}"
získat pole řádků z výstupu příkazu.