When does a shell read into memory?

I don't know how to ask this clearly, so I'll try my best...

At what point does a shell script stop reading from a file, and begin using the buffered script?

Hopefully, this example will shed some light:

#!/usr/bin/ksh

value=""
until [ "$value" = "quit" ]; do
sleep 10
print "What is your value?"
#print "Value, please: \c"
read value
done

echo Hi
echo Lo

Now, if I execute this in the background, it will just wait for me.
During that time, if I edit tmp.sh, and uncomment the "Value Please" line, and comment out the "What is your value" line, it will continue with "What is your value".
If I comment out the "echo Lo" line, before I type "quit", the change is effective when the script completes.

As I understand it, the shells reads the loop into memory, and loops away... It doesn't seem to read the rest of the script in until I get to that part of the script...

Is there some documentation on this (as far as which circumstances will cause the shell to read ahead or not)?

I can provide other examples, if this one makes no sense (well, as much as it could, considering the silliness of a self-rewriting script, or the dangerous nature of modifying a script that is currently running....)

Dave Korn's book on ksh fully documents this behavior with respect to his shell. I am, of course, properly aghast that you would edit a running shell script. But this has implications with aliases which are processed when a command is read. I don't have the book in front of me, but here is an approximation of one of his examples:

#! /usr/bin/ksh
alias xxx="echo one"
if [[ 1 != 0 ]] ; then
       alias xxx="echo two"
       xxx
fi
xxx
exit 0

This will print:
one
two

When I use aliases in a complex way, I will just fall back on eval. Replacing the first xxx command with "eval xxx" yields the expected result.

I'm not sure if I trust my memory on this, but I think that compound commands are read completely before execution. And, IIRC, so are dot scripts.

By editing a running script, you are going to stumble on two additional issues though. The first is buffering. I doubt very much that ksh issues individual read() system calls until it exactly acquires the last new line character that completes it's current compound command. Instead, I would guess that an unknown number of other characters have been pre-read into a buffer awaiting the next read. And this could easily be implementation dependent. The next problem is varying line length. You seem to be envisioning that ksh remembers the last line number read and somehow will resume with the line that follows. Instead ksh will be positioned on a byte number and will read the next byte. You could easily throw it into the middle of a line.

Which makes sense, as I have seen it do some wierd stuff when playing with this the other day...
One of the first things we noticed (I wish I could remember what script we were playing with, since it exhibited this behavior), is that I could have a valid command, like "echo hello", that after changing, would cause the script to error out, complaining:
./tmp.sh: beho: command not found
We tried to control which bytes it overwrote, but were unable to control it in any usable manner...

Hmm, and for some reason, that script doesn't work in bash... It says "xxx: not found" for both of them...

Perplexed as ever :stuck_out_tongue:

For bash, it looks like you need to add a line to the the top of the script to enable aliases:
shopt -s expand_aliases

From the man page:

I never realized that before now. I guess it's since I can't think of a time when I've ever used aliases in a bash script...

In fact, I don't think I've ever used shopt before either, although I use disown every now and again...