I am using Rscript more and more where I would have normally used bash scripts. One small annoyance is that many of these scripts loop over some system()
call that leaves basically no time for R to catch my control-c if I try to interrupt it. Instead it just aborts the system command that was running and continues on to the next loop iteration. For example, when I try to interrupt the following by holding down control-c, it still makes it through all the iterations:
for(i in 1:10) {
cat(i)
system('sleep 3')
}
So far I have always just hacked around this by inserting a small pause in each loop like
for(i in 1:10) {
Sys.sleep(0.25)
cat(i)
system('sleep 3')
}
that will let me abort within an iteration or two if I hold down control-c, but I'm wondering, is there a more efficient way to accomplish this behavior?
John, I'm not sure if this will help, but from investigating setTimeLimit
, I learned that it can halt execution whenever a user is able to execute an interrupt, like Ctrl-C. See this question for some of the references.
In particular, callbacks may be the way to go, and I'd check out addTaskCallback
and this guide on developer.r-project.org.
Here are four other suggestions:
Although it's a hack, a very different approach my be to invoke two R sessions, one is a master session and the other simply exists to execute shell commands passed by the master session, which solely waits for a confirmation that the job was done before starting the next one.
If you can use foreach
instead of for
(either in parallel, via %dopar%, or serial %do% rather than %dopar% or w/ only 1 registered worker), this may be more amenable to interruptions, as it may be equivalent to the first suggestion (since it forks R).
If you can retrieve the exit code for the external command, then that could be passed to a loop conditional. This previous Q&A will be helpful in that regard.
If you want to have everything run in a bash script, then R could just write one long script (i.e. output a string or series of strings to a file). This could be executed and the interrupt is guaranteed not to affect a loop, as you've unrolled the loop. Alternatively, you could write loops in bash. Here are examples. Personally, I like to apply commands to files using find
(e.g. find .... -exec doStuff {} ';'
) or as inputs via backquotes. Unfortunately, I can't easily give well-formatted code on SO, since it embeds backquotes inside of backquotes... See this page for examples So, it may be the case that you could have one command, no looping, and apply a function to all files meeting a particular set of criteria. Using command substitution via backquotes is a very handy trick for a bash user.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With