Obecné pravidlo:citujte jej, pokud může být prázdný nebo může obsahovat mezery (nebo skutečně jakékoli mezery) nebo speciální znaky (zástupné znaky). Necitování řetězců s mezerami často vede k tomu, že shell rozdělí jeden argument na mnoho.
$?
nepotřebuje uvozovky, protože se jedná o číselnou hodnotu. Zda $URL
potřeby to závisí na tom, co tam povolíte a jestli stále chcete argument, pokud je prázdný.
Mám tendenci vždy citovat řetězce jen ze zvyku, protože je to tak bezpečnější.
Stručně řečeno, citujte vše, kde nevyžadujete, aby shell provedl rozdělení tokenu a rozšíření zástupných znaků.
Jednoduché uvozovky chrání text mezi nimi doslovně. Je to správný nástroj, když potřebujete zajistit, aby se mušle vůbec nedotýkala provázku. Obvykle je to preferovaný mechanismus citování, když nevyžadujete proměnnou interpolaci.
$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.
Dvojité uvozovky jsou vhodné, když je vyžadována variabilní interpolace. S vhodnými úpravami je to také dobré řešení, když potřebujete jednoduché uvozovky v řetězci. (Neexistuje žádný přímočarý způsob, jak uniknout z jednoduchých uvozovek, protože uvnitř jednoduchých uvozovek neexistuje žádný mechanismus escapování -- pokud by existoval, necitovaly by úplně doslovně.)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
Žádné uvozovky nejsou vhodné, když konkrétně požadujete, aby shell provedl rozdělení tokenu a/nebo rozšíření zástupných znaků.
Rozdělení tokenu;
$ words="foo bar baz"
$ for word in $words; do
> echo "$word"
> done
foo
bar
baz
Naproti tomu:
$ for word in "$words"; do echo "$word"; done
foo bar baz
(Smyčka běží pouze jednou, přes jediný řetězec v uvozovkách.)
$ for word in '$words'; do echo "$word"; done
$words
(Smyčka běží pouze jednou, přes doslovný řetězec v jednoduchých uvozovkách.)
Rozšíření zástupných znaků:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
Naproti tomu:
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(Neexistuje žádný soubor s doslovným názvem file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(Neexistuje žádný soubor s názvem $pattern
, buď!)
Konkrétněji řečeno, vše, co obsahuje název souboru, by mělo být obvykle uvozováno (protože názvy souborů mohou obsahovat mezery a další metaznaky shellu). Vše, co obsahuje adresu URL, by mělo být obvykle v uvozovkách (protože mnoho adres URL obsahuje metaznaky shellu jako ?
a &
). Vše, co obsahuje regulární výraz, by mělo být obvykle citováno (stejně jako). Cokoli, co obsahuje významné mezery jiné než jednotlivé mezery mezi znaky, které nejsou mezery, je třeba uvést v uvozovkách (protože jinak shell rozdělí mezery na, efektivně, jednotlivé mezery, a ořízne všechny mezery na začátku nebo na konci).
Když víte, že proměnná může obsahovat pouze hodnotu, která neobsahuje žádné metaznaky shellu, je uvozování nepovinné. Tedy $?
bez uvozovek je v zásadě v pořádku, protože tato proměnná může vždy obsahovat pouze jediné číslo. Nicméně "$?"
je také správné a doporučuje se pro obecnou konzistentnost a správnost (ačkoli toto je moje osobní doporučení, nikoli široce uznávaná zásada).
Hodnoty, které nejsou proměnnými, se v zásadě řídí stejnými pravidly, i když pak můžete také uniknout libovolným metaznakům místo jejich citování. Běžným příkladem je adresa URL s &
v něm bude analyzován shellem jako příkaz na pozadí, pokud není metaznak escapován nebo uvozován:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Samozřejmě k tomu také dochází, pokud je adresa URL v proměnné bez uvozovek.) U statického řetězce dávají největší smysl jednoduché uvozovky, i když zde funguje jakákoli forma uvozovek nebo escapování.
wget 'http://example.com/q&uack' # Single quotes preferred for a static string
wget "http://example.com/q&uack" # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack # Backslash escape
wget http://example.com/q'&'uack # Only the metacharacter really needs quoting
Poslední příklad také naznačuje další užitečný koncept, který rád nazývám „houpací citace“. Pokud potřebujete kombinovat jednoduché a dvojité uvozovky, můžete je použít vedle sebe. Například následující řetězce v uvozovkách
'$HOME '
"isn't"
' where `<3'
"' is."
lze vložit dohromady zády k sobě a vytvořit jeden dlouhý řetězec po tokenizaci a odstranění citace.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Není to špatně čitelné, ale je to běžná technika, a proto je dobré ji znát.
Kromě toho by skripty obvykle neměly používat ls
na cokoliv. Chcete-li rozšířit zástupný znak, stačí ... jej použít.
$ printf '%s\n' $pattern # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern; do # definitely, definitely not ``for file in $(ls $pattern)''
> printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt
(Ve druhém příkladu je smyčka zcela nadbytečná; printf
konkrétně funguje dobře s více argumenty. stat
také. Ale opakování shody zástupných znaků je běžný problém a často se provádí nesprávně.)
Proměnná obsahující seznam tokenů k opakování nebo zástupný znak k rozbalení se vyskytuje méně často, takže někdy zkracujeme na „citujte vše, pokud přesně nevíte, co děláte“.
Zde je tříbodový vzorec pro uvozovky obecně:
Dvojité uvozovky
V kontextech, kde chceme potlačit štěpení slov a globování. Také v kontextech, kde chceme, aby byl literál považován za řetězec, nikoli za regulární výraz.
Jednoduché uvozovky
V řetězcových literálech, kde chceme potlačit interpolaci a speciální úpravu zpětných lomítek. Jinými slovy, situace, kdy by použití dvojitých uvozovek bylo nevhodné.
Žádné uvozovky
V kontextech, kdy jsme si naprosto jisti, že nedochází k problémům s dělením slov nebo globbingem nebo chceme dělení a globování slov .
Příklady
Dvojité uvozovky
- doslovné řetězce s mezerami (
"StackOverflow rocks!"
,"Steve's Apple"
) - rozšíření proměnných (
"$var"
,"${arr[@]}"
) - záměny příkazů (
"$(ls)"
,"`ls`"
) - globs, kde cesta k adresáři nebo část názvu souboru obsahuje mezery (
"/my dir/"*
) - pro ochranu jednoduchých uvozovek (
"single'quote'delimited'string"
) - Rozšíření parametrů Bash (
"${filename##*/}"
)
Jednoduché uvozovky
- názvy příkazů a argumenty, které obsahují mezery
- doslovné řetězce, které vyžadují potlačení interpolace (
'Really costs $$!'
,'just a backslash followed by a t: \t'
) - pro ochranu dvojitých uvozovek (
'The "crux"'
) - literály regulárních výrazů, které vyžadují potlačení interpolace
- použijte citace shellu pro literály obsahující speciální znaky (
$'\n\t'
) - použijte shellové uvozovky tam, kde potřebujeme chránit několik jednoduchých a dvojitých uvozovek (
$'{"table": "users", "where": "first_name"=\'Steve\'}'
)
Žádné uvozovky
- kolem standardních číselných proměnných (
$$
,$?
,$#
atd.) - v aritmetických kontextech, jako je
((count++))
,"${arr[idx]}"
,"${string:start:length}"
- uvnitř
[[ ]]
výraz, který neobsahuje problémy s rozdělováním slov a globováním (toto je věc stylu a názory se mohou značně lišit) - kde chceme rozdělení slov (
for word in $words
) - kde chceme globbing (
for txtfile in *.txt; do ...
) - kde chceme
~
být interpretován jako$HOME
(~/"some dir"
ale ne"~/some dir"
)
Viz také:
- Rozdíl mezi jednoduchými a dvojitými uvozovkami v Bash
- Co jsou speciální proměnné shellu znaku dolaru?
- Citáty a escapování – Wiki Bash Hackers
- Kdy je nutné dvojité uvozování?