I start my Rails development processes by using AppleScript to set up iTerm2. I often need to restart my Rails processes when I change something in config/initializers, or if I add a new gem to the Gemfile.

I wanted to create a “restart loop” so that pressing Ctrl+C would stop the process and then restart it. I also wanted to have the option to break out of the loop and get back to the bash prompt.

The solution was to handle INT in the Bash subshell with trap true INT, while allowing the foreground process to receive Ctrl+C. The loop pauses for half a second between runs. Press Ctrl+C during that pause to interrupt sleep and leave the loop; pressing it twice works only if the second press lands in that window.

Here’s the command I’m running to start the Rails server with a restart loop:

(trap true INT; while sleep 0.5; do echo 'Starting Rails...'; \
  rails server --binding=127.0.0.1 --port 3000; done)

In my .dev.scpt script, I’m now using a subroutine to wrap all the commands:

on commandWithRestartLoop(label, command)
  return "(trap true INT; while sleep 0.5; do " & ¬
    "echo 'Starting " & label & "...'; " & ¬
    command & "; done)"
end commandWithRestartLoop
# ...
write text my commandWithRestartLoop("Rails", ¬
  "rails server --binding=127.0.0.1 --port 3000")
# ...
write text my commandWithRestartLoop("Sidekiq", "sidekiq")