4

Please consider this bash-script:

#!/bin/bash

trap '' INT

echo sleep:  
sleep 5

echo rsync:  
rsync -a /usr/lib /var/tmp

Trying to interrupt sleep with ctrl-c fails, as expected. But rsync is interruptible (the order of sleep & rsync doesn't matter)? Any ideas are welcome!

Edit: Found a difference: rsync itself starts 2 child procs (client/server, which produce the 2 error msgs, i assume), and these seem not to inherit the 'ignorance' of its parent. Must dive into bash sources and find out how trap is working...

Jolta
  • 2,620
  • 1
  • 29
  • 42
  • 1
    `rsync` is setting its own signal handler, overriding yours? – tripleee Nov 26 '12 at 20:03
  • Here is a link to a very similar problem. Looking there might help. http://stackoverflow.com/questions/9624947/bash-not-trapping-interrupts-during-rsync-subshell-exec-statements – davak Nov 26 '12 at 20:18
  • thanks for the link, but i had read that one yet. but the solution to that problem didn't help me - or i haven't unterstand it the right way :/ @tripleee: then the trap is useless? why does the ctrl-c go 'through' the shell? – user1854128 Nov 26 '12 at 21:37
  • The shell does (more or less): `signal(SIGINT, SIG_IGN)`. Any child process (such as `rsync`) inherits ignored signal handling. However, if `rsync` carelessly and unconditionally does `signal(SIGINT, sigint_handler)`, that undoes the shell's attempt to protect it from interrupts. That's why the books always advise you test: `if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, sigint_handler);`. All this is at the C code level, of course. – Jonathan Leffler Nov 26 '12 at 22:21
  • Thanks Jonathan for your detailed explanation. Now it's clearer. – user1854128 Nov 27 '12 at 17:10

2 Answers2

4

Have you tried using rsync with --no-detach as advised in the SO question bash not trapping interrupts during rsync subshell/exec statements?

Community
  • 1
  • 1
davak
  • 313
  • 3
  • 6
3

It's pretty clear from experimentation that rsync behaves like other tools such as ping and do not inherit signals from the calling Bash parent.

So you have to get a little creative with this and do something like the following:

$ cat rsync.bash
#!/bin/sh

 set -m
 trap '' SIGINT SIGTERM EXIT
 rsync -avz LargeTestFile.500M root@host.mydom.com:/tmp/. &
 wait

 echo FIN

Now when I run it:

$ ./rsync.bash
X11 forwarding request failed
building file list ... done
LargeTestFile.500M
^C^C^C^C^C^C^C^C^C^C
sent 509984 bytes  received 42 bytes  92732.00 bytes/sec
total size is 524288000  speedup is 1027.96
FIN

And we can see the file did fully transfer:

$ ll -h | grep Large
-rw-------. 1  501 games 500M Jul  9 21:44 LargeTestFile.500M

How it works

The trick here is we're telling Bash via set -m to disable job controls on any background jobs within it. We're then backgrounding the rsync and then running a wait command which will wait on the last run command, rsync, until it's complete.

We then guard the entire script with the trap '' SIGINT SIGTERM EXIT.

References

slm
  • 15,396
  • 12
  • 109
  • 124