Yes shells, and
bash in particular, are careful to read the file one line at a time, so it works the same as when you use it interactively.
You'll notice that when the file is not seekable (like a pipe),
bash even reads one byte at a time to be sure not to read past the
\n character. When the file is seekable, it optimises by reading full blocks at a time, but seek back to after the
That means you can do things like:
bash << \EOF
Or write scripts that update themselves. Which you wouldn't be able to do if it didn't give you that guarantee.
Now, it's rare that you want to do things like that and, as you found out, that feature tends to get in the way more often than it is useful.
To avoid it, you could try and make sure you don't modify the file in-place (for instance, modify a copy, and move the copy in place (like
sed -i or
perl -pi and some editors do for instance)).
Or you could write your script like:
(note that it's important that the
exit be on the same line as
}; though you could also put it inside the braces just before the closing one).
main "$@"; exit
The shell will need to read the script up until the
exit before starting to do anything. That ensures the shell will not read from the script again.
That means the whole script will be stored in memory though.
That can also affect the parsing of the script.
For instance, in
Would output that U+00E9 encoded in UTF-8. However, if you change it to:
\ue9 will be expanded in the charset that was in effect at the time that command was parsed which in this case is before the
export command is executed.
Also note that if the
. command is used, with some shells, you'll have the same kind of problem for the sourced files.
That's not the case of
bash though whose
source command reads the file fully before interpreting it. If writing for
bash specifically, you could actually make use of that, by adding at the start of the script:
if [[ ! $already_sourced ]]; then
source "$0"; exit
(I wouldn't rely on that though as you could imagine future versions of
bash could change that behaviour which can be currently seen as a limitation (bash and AT&T ksh are the only POSIX-like shells that behave like that as far as can tell) and the
already_sourced trick is a bit brittle as it assumes that variable is not in the environment, not to mention that it affect the content of the BASH_SOURCE variable)