bash usually does not load the entire script in advance, so rewriting the script can have unpredictable consequences. For example, I just created a script containing this:
#!/bin/bash echo start old file sleep 20 echo end old file
... and launched it. While he was sleeping, I overwrote it with a slightly different script:
#!/bin/bash echo started new file sleep 20 echo end new file
Resulting result:
$ ./test.sh start old file ./test.sh: line 4: 0: command not found end new file
It so happened that bash read the line "sleep 20 \ n" (including the line ending a new line) before going to bed. When he continued after that, he read the next command from the next byte position in the file, and since the second line received two bytes longer ("start" → "start"), she finished reading the last two bytes with a new sleep line ("sleep 20 \ n "→" 0 \ n "), trying to execute the" 0 "command as a command and get an error message. Then it launches the last line of new content. Pretty dirty, right?
Fortunately, there is a way to get bash to load the entire script into memory so that it doesn't get confused if it changes during runtime:
#!/bin/bash { echo start old file sleep 20 echo end old file exit }
{ forces the shell to read at least through matching } to correctly parse this command, and exit will then make sure that it never tries to execute anything added after that } .
By the way, I tested this with bash version 3.2.48 (1) -release (on OS X 10.8.5); other versions may behave differently ...
UPDATE: Other versions do behave differently. I tried the same test with version 4.3.0 (1) -release (under NetBSD 6.1.4), and it continued to run the old code after replacing the contents of the file. Apparently, it is now buffering the file in 8KB blocks (see this unix.se answer ).
Gordon davisson
source share