Sì, le shell, e bash
in particolare, stanno attenti a leggere il file una riga alla volta, quindi funziona allo stesso modo di quando lo usi in modo interattivo.
Noterai che quando il file non è ricercabile (come una pipe), bash
legge anche un byte alla volta per essere sicuro di non leggere oltre il \n
carattere. Quando il file è ricercabile, si ottimizza leggendo i blocchi completi alla volta, ma cerca nuovamente dopo \n
.
Ciò significa che puoi fare cose come:
bash << \EOF
read var
var's content
echo "$var"
EOF
Oppure scrivi script che si aggiornano da soli. Cosa che non saresti in grado di fare se non ti desse quella garanzia.
Ora, è raro che tu voglia fare cose del genere e, come hai scoperto, quella caratteristica tende a interferire più spesso di quanto sia utile.
Per evitarlo, puoi provare ad assicurarti di non modificare il file sul posto (ad esempio, modificare una copia e spostare la copia in posizione (come sed -i
o perl -pi
e alcuni editor lo fanno ad esempio)).
Oppure potresti scrivere la tua sceneggiatura come:
{
sleep 20
echo test
}; exit
(nota che è importante exit
essere sulla stessa linea di }
; anche se potresti anche metterlo tra le parentesi appena prima di quello di chiusura).
o:
main() {
sleep 20
echo test
}
main "$@"; exit
La shell dovrà leggere lo script fino a quando exit
prima di iniziare a fare qualsiasi cosa. Ciò garantisce che la shell non leggerà più dallo script.
Ciò significa che l'intero script verrà comunque archiviato in memoria.
Ciò può anche influire sull'analisi dello script.
Ad esempio, in bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Emetterebbe U + 00E9 codificato in UTF-8. Tuttavia, se lo cambi in:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
Il \ue9
sarà ampliato nel charset che era in vigore al momento che il comando è stato analizzato che in questo caso è prima il export
viene eseguito il comando.
Si noti inoltre che se si utilizza il comando source
aka .
, con alcune shell, si avrà lo stesso tipo di problema per i file di origine.
Questo non è il caso di chi, il bash
cui source
comando legge il file completamente prima di interpretarlo. Se si scrive in modo bash
specifico, è possibile utilizzarlo aggiungendo all'inizio dello script:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Non farei affidamento su questo, anche se, come puoi immaginare, le versioni future bash
potrebbero cambiare quel comportamento che può essere attualmente visto come una limitazione (bash e AT&T ksh sono le uniche shell tipo POSIX che si comportano in questo modo per quanto ne so) e il already_sourced
trucco è un po 'fragile in quanto presuppone che la variabile non sia nell'ambiente, per non parlare del fatto che influenza il contenuto della variabile BASH_SOURCE)