A habit I'm thinking of adopting for my shell scripting:

Write scripts in the form of a sequence of function definitions, with no commands at the top level that actually do anything. Then, at the very end, write a compound statement that calls one of the functions and ends with an exit. Like this:

#!/bin/bash
subroutine() { ... }
main() { ... }
{ main "$@"; exit $?; }

The idea is that the shell doesn't actually _do_ anything while reading this script until it reads the braced compound statement at the end. And then it's committed to exiting during the execution of that statement. So it won't ever read from the script file again.

With a normal shell script, it's dangerous to edit the script file while an instance of the shell is still running it, because the shell will read from the modified version of the file starting at the file position it had got to in the old one, perhaps reading a partial command or the wrong command and doing something you didn't want. But with a script in this style, the shell finishes reading the script before it does anything, so it's safe to edit.

(Of course, if your editor saves the new script file to a different file name and renames it over the top, you're safe anyway. But not all editors do: emacs, in particular, reopens the existing file and overwrites its contents.)

@simontatham Wow, I thought only cmd.exe was dumb enough to not make a copy of the script in memory before starting to execute it.

@phairupegiont @simontatham I suspect the reason the shell "runs in place" is because running code from standard input is a "feature":

echo 'typeset -p PWD' | sh

https://pubs.opengroup.org/onlinepubs/009604499/utilities/sh.html

sh

@march38 @simontatham
Yeah ok, when running from stdin, not buffering everything first is fine, because what is read cannot be modified afterwards.

But when running from a file, I just don't see a reason not to buffer it first.

@phairupegiont @march38 ah, here's a thought – some shell scripts are _incredibly big_ and composed mostly of a here-document. 'shar' archives spring to mind. When shar was popular, computers were also smaller, so quite likely there would have been archive scripts so big that the shell would run out of memory buffering the whole thing in RAM before running it!

@simontatham @march38
Ok, shell archives are a case where buffering is unwanted.

A case that looks like it would be solved by having a flag in the shebang to disable input buffering...