Question

I often have to relaunch a server to see if my changes are fine. I keep this server opened in a shell, so I have a quick access to current logs. So here is what I type in my shell: ^C!!⏎. That is send SIGINT, and then relaunch last event in history.

So what I would like is to type, say ^R, and have the same result.

(Note: I use zsh)

I tried the following:

relaunch-function() {
        kill -INT %% && !!
}
zle -N relaunch-widget relaunch-function
bindkey "^R" relaunch-widget

But it seems that while running my server, ^R won't be passed tho the shell but to the server which doesn't notice the shell. So I can't see a generic solution, while testing return value and process name should be feasible.

Was it helpful?

Solution

As long as the job is running in the foreground, keys will not be passed to the shell. So setting a key binding for killing a foreground process and starting it again won't work.

But as you could start your server in an endless loop, so that it restarts automatically. Assuming the name of the command is run_server you can start it like this on the shell:

(TRAPINT(){};while sleep .5; do run_server; done)

The surrounding parentheses start a sub-shell, TRAPINT(){} disables SIGINT for this shell. The while loop will keep restarting run_server until sleep exits with an exit status that is not zero. That can be achieved by interrupting sleep with ^C. (Without setting TRAPINT, interrupting run_server could also interrupt the loop)

So if you want to restart your server, just press ^C and wait for 0.5 seconds. If you want to stop your server without restarting, press ^C twice in 0.5 seconds.

To save some typing you can create a function for that:

doloop() {(
    TRAPINT(){}
    while sleep .5
    do
        echo running \"$@\"
        eval $@
    done   
)}

Then call it with doloop run_server. Note: You still need the additional surrounding () as functions do not open a sub-shell by themselves.

eval allows for shell constructs to be used. For example doloop LANG=C locale. In some cases you may need to use (single):

$ doloop echo $RANDOM
running "echo 242"
242
running "echo 242"
242
running "echo 242"
242
^C
$ doloop 'echo $RANDOM'
running "echo $RANDOM"
10988
running "echo $RANDOM"
27551
running "echo $RANDOM"
8910
^C
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top