Obvykle, pokud upravujete skript, všechna použití skriptu jsou náchylná k chybám.
Pokud tomu dobře rozumím, bash (i jiné shelly?) čte skript postupně, takže pokud jste soubor skriptu upravili externě, začne číst nesprávné věci. Existuje nějaký způsob, jak tomu zabránit?
Příklad:
sleep 20
echo test
Pokud tento skript spustíte, bash přečte první řádek (řekněme 10 bajtů) a usne. Když se obnoví, může být ve skriptu různý obsah začínající na 10. bajtu. Možná jsem uprostřed řádku v novém skriptu. Spuštěný skript tak bude přerušen.
Přijatá odpověď:
Ano shelly a bash
zejména dávejte pozor, abyste soubor četl jeden řádek po druhém, takže to funguje stejně, jako když jej používáte interaktivně.
Všimnete si, že když soubor nelze vyhledat (jako potrubí), bash
dokonce čte jeden bajt po druhém, abyste si byli jisti, že nečte za \n
charakter. Když je soubor vyhledatelný, optimalizuje se čtením celých bloků najednou, ale přejde zpět za \n
.
To znamená, že můžete dělat věci jako:
bash << \EOF
read var
var's content
echo "$var"
EOF
Nebo pište skripty, které se samy aktualizují. Což byste nemohli udělat, kdyby vám to nedávalo tuto záruku.
Nyní je vzácné, že chcete dělat takové věci, a jak jste zjistili, tato funkce má tendenci překážet častěji, než je užitečná.
Abyste se tomu vyhnuli, můžete se pokusit ujistit se, že soubor neupravíte na místě (například upravíte kopii a přesunete kopii na místo (jako sed -i
nebo perl -pi
a někteří editoři to například dělají)).
Nebo můžete napsat svůj skript jako:
{
sleep 20
echo test
}; exit
(Všimněte si, že je důležité, aby exit
být na stejném řádku jako }
; i když byste ho také mohli vložit do závorek těsně před zavíracím.
nebo:
main() {
sleep 20
echo test
}
main "[email protected]"; exit
Shell bude muset číst skript až do exit
než začnete něco dělat. To zajišťuje, že shell nebude znovu číst ze skriptu.
To znamená, že celý skript bude uložen v paměti.
To může také ovlivnit analýzu skriptu.
Například v bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Výstup by U+00E9 zakódovaný v UTF-8. Pokud jej však změníte na:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
\ue9
bude rozšířena ve znakové sadě, která byla platná v době, kdy byl příkaz analyzován, což je v tomto případě před export
příkaz se provede.
Všimněte si také, že pokud source
aka .
Pokud se používá příkaz, u některých shellů budete mít stejný problém se zdrojovými soubory.
To není případ bash
ačkoli jehož source
příkaz přečte soubor před jeho interpretací. Pokud píšete pro bash
konkrétně byste to mohli skutečně využít přidáním na začátek skriptu:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Na to bych se však nespoléhal, protože si dokážete představit budoucí verze bash
mohl změnit toto chování, které lze v současnosti považovat za omezení (bash a AT&T ksh jsou jediné shelly podobné POSIXu, které se takto chovají, pokud lze říci) a already_sourced
trik je trochu křehký, protože předpokládá, že proměnná není v prostředí, nemluvě o tom, že ovlivňuje obsah proměnné BASH_SOURCE)