Edit shell script while it's running
It does affect, at least bash in my environment, but in very unpleasant way. See these codes. First a.sh
:
#!/bin/sh
echo "First echo"
read y
echo "$y"
echo "That's all."
b.sh
:
#!/bin/sh
echo "First echo"
read y
echo "Inserted"
echo "$y"
# echo "That's all."
Do
$ cp a.sh run.sh
$ ./run.sh
$ # open another terminal
$ cp b.sh run.sh # while 'read' is in effect
$ # Then type "hello."
In my case, the output is always:
hello hello That's all. That's all.
(Of course it's far better to automate it, but the above example is readable.)
[edit] This is unpredictable, thus dangerous. The best workaround is , as described here put all in a brace, and before the closing brace, put "exit". Read the linked answer well to avoid pitfalls.
[added] The exact behavior depends on one extra newline, and perhaps also on your Unix flavor, filesystem, etc. If you simply want to see some influences, simply add "echo foo/bar" to b.sh before and/or after the "read" line.
Try this... create a file called bash-is-odd.sh
:
#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh
That demonstrates that bash is, indeed, interpreting the script "as you go". Indeed, editing a long-running script has unpredictable results, inserting random characters etc. Why? Because bash reads from the last byte position, so editing shifts the location of the current character being read.
Bash is, in a word, very, very unsafe because of this "feature". svn and rsync
when used with bash scripts are particularly troubling, because by default they "merge" the results... editing in place. rsync
has a mode that fixes this. svn and git do not.
I present a solution. Create a file called /bin/bashx
:
#!/bin/bash
source "$1"
Now use #!/bin/bashx
on your scripts and always run them with bashx
instead of bash
. This fixes the issue - you can safely rsync
your scripts.
Alternative (in-line) solution proposed/tested by @AF7:
{
# your script
}
exit $?
Curly braces protect against edits, and exit protects against appends. Of course, we'd all be much better off if bash came with an option, like -w
(whole file), or something that did this.
Break your script into functions, and each time a function is called you source
it from a separate file. Then you could edit the files at any time and your running script will pick up the changes next time it gets sourced.
foo() {
source foo.sh
}
foo