Edit shell script while it's running

LinuxShellCsh

Linux Problem Overview


Can you edit a shell script while it's running and have the changes affect the running script?

I'm curious about the specific case of a csh script I have that batch runs a bunch of different build flavors and runs all night. If something occurs to me mid operation, I'd like to go in and add additional commands, or comment out un-executed ones.

If not possible, is there any shell or batch-mechanism that would allow me to do this?

Of course I've tried it, but it will be hours before I see if it worked or not, and I'm curious about what's happening or not happening behind the scenes.

Linux Solutions


Solution 1 - Linux

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.

Solution 2 - Linux

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.

Solution 3 - Linux

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

Solution 4 - Linux

Good question! Hope this simple script helps

#!/bin/sh
echo "Waiting..."
echo "echo \"Success! Edits to a .sh while it executes do affect the executing script! I added this line to myself during execution\"  " >> ${0}
sleep 5
echo "When I was run, this was the last line"

It does seem under linux that changes made to an executing .sh are enacted by the executing script, if you can type fast enough!

Solution 5 - Linux

An interesting side note - if you are running a Python script it does not change. (This is probably blatantly obvious to anyone who understands how shell runs Python scripts, but thought it might be a useful reminder for someone looking for this functionality.)

I created:

#!/usr/bin/env python3
import time
print('Starts')
time.sleep(10)
print('Finishes unchanged')

Then in another shell, while this is sleeping, edit the last line. When this completes it displays the unaltered line, presumably because it is running a .pyc? Same happens on Ubuntu and macOS.

Solution 6 - Linux

I don't have csh installed, but

#!/bin/sh
echo Waiting...
sleep 60
echo Change didn't happen

Run that, quickly edit the last line to read

echo Change happened

Output is

Waiting...
/home/dave/tmp/change.sh: 4: Syntax error: Unterminated quoted string

Hrmph.

I guess edits to the shell scripts don't take effect until they're rerun.

Solution 7 - Linux

If this is all in a single script, then no it will not work. However, if you set it up as a driver script calling sub-scripts, then you might be able to change a sub-script before it's called, or before it's called again if you're looping, and in that case I believe those changes would be reflected in the execution.

Solution 8 - Linux

Use Zsh instead for your scripting.

AFAICT, Zsh does not exhibit this frustrating behavior.

Solution 9 - Linux

I'm hearing no... but what about with some indirection:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Then you should be able to edit the contents of each command file before BatchRunner gets to it right?

OR

A cleaner version would have BatchRunner look to a single file where it would consecutively run one line at a time. Then you should be able to edit this second file while the first is running right?

Solution 10 - Linux

usually, it uncommon to edit your script while its running. All you have to do is to put in control check for your operations. Use if/else statements to check for conditions. If something fail, then do this, else do that. That's the way to go.

Solution 11 - Linux

Scripts don't work that way; the executing copy is independent from the source file that you are editing. Next time the script is run, it will be based on the most recently saved version of the source file.

It might be wise to break out this script into multiple files, and run them individually. This will reduce the execution time to failure. (ie, split the batch into one build flavor scripts, running each one individually to see which one is causing the trouble).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionackView Question on Stackoverflow
Solution 1 - Linuxteika kazuraView Answer on Stackoverflow
Solution 2 - LinuxErik AronestyView Answer on Stackoverflow
Solution 3 - Linuxglenn jackmanView Answer on Stackoverflow
Solution 4 - LinuxWill TurnerView Answer on Stackoverflow
Solution 5 - LinuxChrisView Answer on Stackoverflow
Solution 6 - Linuxdave4420View Answer on Stackoverflow
Solution 7 - LinuxEthan ShepherdView Answer on Stackoverflow
Solution 8 - LinuxMicah ElliottView Answer on Stackoverflow
Solution 9 - LinuxackView Answer on Stackoverflow
Solution 10 - Linuxghostdog74View Answer on Stackoverflow
Solution 11 - LinuxfordView Answer on Stackoverflow