V mém prostředí Bash používám proměnné obsahující mezery a tyto proměnné používám v rámci substituce příkazů.
Jaký je správný způsob citování mých proměnných? A jak to mám udělat, pokud jsou vnořené?
DIRNAME=$(dirname "$FILE")
nebo cituji mimo substituci?
DIRNAME="$(dirname $FILE)"
nebo obojí?
DIRNAME="$(dirname "$FILE")"
nebo mám použít back-ticks?
DIRNAME=`dirname "$FILE"`
Jaký je správný způsob, jak to udělat? A jak mohu snadno zkontrolovat, zda jsou uvozovky nastaveny správně?
Přijatá odpověď:
V pořadí od nejhoršího k nejlepšímu:
DIRNAME="$(dirname $FILE)"nebude dělat to, co chcete, pokud$FILEobsahuje mezery (nebo jakékoli jiné znaky$IFSaktuálně obsahuje) nebo globbing znaky[?*.DIRNAME=`dirname "$FILE"`je technicky správná, ale zpětná zaškrtnutí se pro rozšiřování příkazů nedoporučují kvůli mimořádné složitosti při jejich vnořování a zvláštnímu zpracování zpětných lomítek, ke kterému v nich dochází.DIRNAME=$(dirname "$FILE")je správné, ale pouze proto, že se jedná o přiřazení ke skalární (nikoli maticové) proměnné. Pokud použijete substituci příkazu v jakémkoli jiném kontextu, napříkladexport DIRNAME=$(dirname "$FILE")nebodu $(dirname -- "$FILE"), nedostatek uvozovek způsobí potíže, pokud výsledek rozšíření bude obsahovat mezery nebo kulovité znaky.DIRNAME="$(dirname "$FILE")"(kromě chybějícího--, viz níže) je doporučený způsob.DIRNAME=můžete nahradit s příkazem a mezerou beze změny čehokoli jiného adirnamepřijme správný řetězec.
Chcete-li se ještě zlepšit:
DIRNAME="$(dirname -- "$FILE")"funguje, pokud$FILEzačíná pomlčkou.DIRNAME="$(dirname -- "$FILE" && printf x)" && DIRNAME="${DIRNAME%?x}" || exitfunguje, i když$FILE's dirname končí novým řádkem, protože$()odřízne nové řádky na konci výstupu, oba ten přidanýdirnamea ty, které mohou být součástí skutečných dat.
Rozšíření příkazů můžete vnořovat, jak chcete. Pomocí $() vždy vytvoříte nový kontext citací, takže můžete dělat věci jako toto:
foo "$(bar "$(baz "$(ban "bla")")")"
Vy ne chcete to zkusit pomocí zpětných znamének.