Created
August 21, 2012 22:01
-
-
Save hmason/3419831 to your computer and use it in GitHub Desktop.
Did you know that bash will reload a script *while it is executing*?!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
function addnext { | |
NUM=$1 | |
sleep 1 | |
echo HI $NUM | |
NUM=$(expr $NUM + 1) | |
echo addnext $NUM >> $0 | |
} | |
addnext 1 |
Not to split hairs here, but because the file lacks an EOL, this does not work until you edit the file and add a \n
to it.
curl -LO https://gist.githubusercontent.com/hmason/3419831/raw/test.sh; chmod +x ./test.sh; ./test.sh
In other words...
$ curl -LO https://gist.githubusercontent.com/hmason/3419831/raw/test.sh; chmod +x test.sh; ./test.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 122 100 122 0 0 346 0 --:--:-- --:--:-- --:--:-- 346
HI 1
$ cat test.sh
#!/bin/bash
function addnext {
NUM=$1
sleep 1
echo HI $NUM
NUM=$(expr $NUM + 1)
echo addnext $NUM >> $0
}
addnext 1addnext 2
$ curl -LO https://gist.githubusercontent.com/hmason/3419831/raw/test.sh; chmod +x test.sh; echo >> test.sh; ./test.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 122 100 122 0 0 321 0 --:--:-- --:--:-- --:--:-- 321
HI 1
HI 2
HI 3
HI 4
HI 5
HI 6
HI 7
HI 8
HI 9
HI 10
...
A simple strace shows that it is not reloading anything.
script:
#!/bin/bash
num=0
while [[ $num -lt 20 ]] ; do
echo "waiting...$num"
sleep 1s
num=$(( $num + 1 ))
done
echo "I am done!"
open("./run.sh", O_RDONLY) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffda02d2010) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/bin/bash\n\nnum=0\n\nwhile [[ $nu"..., 80) = 80
lseek(3, 0, SEEK_SET) = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 255) = 255
close(3) = 0
fcntl(255, F_SETFD, FD_CLOEXEC) = 0
fcntl(255, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE)
fstat(255, {st_mode=S_IFREG|0775, st_size=128, ...}) = 0
lseek(255, 0, SEEK_CUR) = 0
...
read(255, "#!/bin/bash\n\nnum=0\n\nwhile [[ $nu"..., 128) = 128
...
lseek(255, -20, SEEK_CUR) = 108
...
read(255, "\n\necho \"I am done!\"\n", 128) = 20
read(255, "", 128) = 0
exit_group(0) = ?
I did not check bash source code but I would imagine it would never read the entire script in memory. It should read it by chunks as it executes it. I am not sure why it does that lseek() but probably just to go to the beginning of the last line and continue reading from there. Just a guess. So, the behaviour of the script "changing" one the fly would depend on how the filesystem react to the concurrent reading and writing.
I may be wrong, this is just my guess based on what I would expect and what I see in strace on Linux....
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nothing is surprising about this. bash doesn't need to preprocess its source (there's no bash vm) so why would it first buffer the entire file (which could be very large)?
even if it did buffer the entire file, it would pick up new changes as the file was appended to as it was buffering.