I am rsyncing a few directories. I have a bash terminal open and am executing something like this:

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done

However if I want to stop the whole things, I press Control-C. That stops the rsync, but then it keeps going to the next one. In this case I realize what has happened and then just press Control-C like a madman until things work again.

Is there some way to 'fix' this. I want it so if I have a loop like that, and press Control-C, that it will return me to my bash shell.

  • 7
    Dennis' answer is the right one, but you if you didn't do that, you don't have to 'press it like a madman', just hold it and let the keyboard repeat handle it :-) – Kyle Brandt Jan 22 '10 at 15:52
  • I always just hold down Cntl-C, generally works fine. – Scott Alan Miller Jan 22 '10 at 18:41
for DIR in * ; do rsync -a $DIR example.com:somewhere/ || break; done

This will also exit the loop if an individual rsync run fails for some reason.

  • 6
    Additional tip: if you're in a nested loop, and want to completely terminate, use break 2 (or replace "2" with the number of nested loops you want to terminate). – Dolan Antenucci Jan 23 '13 at 20:33

To expand on Dennis' answer, your code might look like:

trap "echo Exited!; exit;" SIGINT SIGTERM

For a working example (that happens to involve rsync), check out http://gist.github.com/279849.

  • Thanks, this is a generic solution that worked for me – wi1 Jul 30 '18 at 15:14

You can set a trap for Control-C.

trap <command> SIGINT

will execute the command when Control-C is pressed. Just put the trap statement somewhere in your script at a point where you want it to become effective.

  1. Press Ctrl-Z to suspend the script ;
  2. kill %%

Credits, explanations and more details in this answer.

  • This is great because it works "post facto" when you want to interrupt a long-running loop you already started. – Nick Matteo Sep 23 '19 at 17:06
  • the best answer, thank you! – Kostanos Nov 30 '19 at 17:51

When you put a string of commands inside parentheses, the string will act as a single process, and will receive the SIGINT and terminate when you hit Ctrl-C:

(for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done)

But! In the case of the rsync command, it allows multiple sources, so the code you wrote would be better-written as:

rsync -a * example.com:somewhere/

I tend to put another command in my loop that can easily be interrupted. It requires two ctrl-C's to be pressed.

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; sleep 1 ; done

It's not such a great solution for this rsync, which you probably want to run quickly. But it does work well for other loops, like this one:

while true ; do ping -c 10 example.com ; sleep 1 ; done

This loop will re-lookup the address of example.com every time through the loop, which is useful if you're watching for a DNS change.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.