12

Inspired by this answer I am looking for a way to detach several packages at once.

When I load say Hmisc,

# install.packages("Hmisc", dependencies = TRUE)
require(Hmisc)

R also loads survival and splines. My question is if there is a way to unload that group together?

I currently do something like this,

detach(package:Hmisc, unload = T) 
detach(package:survival, unload = T) 
detach(package:splines, unload = T)

I tried,

detach(package:c('Hmisc', 'survival', 'splines'), unload = T)

Community
  • 1
  • 1
Eric Fail
  • 8,191
  • 8
  • 72
  • 128
  • 1
    I would be very cautious about group detaching, because it's always possible that you have some **other** package in use which also depends on one of the subordinate packages. Sort of like the near-impossibility of figuring out which Windows DLLs can safely be removed when uninstalling some app :-( . – Carl Witthoft Jul 09 '13 at 13:40
  • @CarlWitthoft, thank you for your thoughtful comment. – Eric Fail Jul 09 '13 at 16:33
  • 2
    @CarlWitthoft `detach` does check for dependences and will refuse to detach packages that are required by others in use. You can override this by `force=TRUE`, but that's on your own head, of course. – Hong Ooi Jul 09 '13 at 17:30
  • @HongOoi -- thanks. I skimmed right over that part. Sorry. – Carl Witthoft Jul 09 '13 at 17:32

4 Answers4

11

Another option:

Vectorize(detach)(name=paste0("package:", c("Hmisc","survival","splines")), unload=TRUE, character.only=TRUE)
Ferdinand.kraft
  • 12,579
  • 10
  • 47
  • 69
5

?detach explicitly rules out supplying a character vector (as opposed to scalar, ie more than one library to be detached) as its first argument, but you can always make a helper function. This will accept multiple inputs that can be character strings, names, or numbers. Numbers are matched to entries in the initial search list, so the fact that the search list dynamically updates after each detach won't cause it to break.

mdetach <- function(..., unload = FALSE, character.only = FALSE, force = FALSE)
{
    path <- search()
    locs <- lapply(match.call(expand=FALSE)$..., function(l) {
        if(is.numeric(l))
            path[l]
        else l
    })
    lapply(locs, function(l)
        eval(substitute(detach(.l, unload=.u, character.only=.c, force=.f),
        list(.l=l, .u=unload, .c=character.only, .f=force))))
    invisible(NULL)
}

library(xts) # also loads zoo

# any combination of these work
mdetach(package:xts, package:zoo, unload=TRUE)
mdetach("package:xts", "package:zoo", unload=TRUE)
mdetach(2, 3, unload=TRUE)

The messing with eval(substitute(... is necessary because, unless character.only=TRUE, detach handles its first argument in a nonstandard way. It checks if it's a name, and if so, uses substitute and deparse to turn it into character. (The character.only argument is misnamed really, as detach(2, character.only=TRUE) still works. It should really be called "accept.names" or something.)

Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • Thanks. Feel guilty as I should have read the `?detach` more carefully. Again, thank you for your answer. – Eric Fail Jul 09 '13 at 13:03
  • 1
    @EricFail No reason to feel guilty. It's a good question, and the complexity of the answer indicates it's not trivial. – Ari B. Friedman Jul 09 '13 at 13:28
  • 1
    Can you elaborate on why `detlist<-c('Hmisc','survival','splines'); lapply(detlist, function(k) detach(k,unload=true))` does not work? The help page says arguments which are strings are acceptable to `detach` . (each argument is a one-element string, rather than a vector of characters if I read it right) – Carl Witthoft Jul 09 '13 at 13:38
  • I didn't downvote, but I don't understand why so much trouble for a vectorization. – Ferdinand.kraft Jul 09 '13 at 18:00
  • @Ferdinand.kraft Just being complete, I guess. Besides, being able to detach by numeric index is nice. – Hong Ooi Jul 09 '13 at 18:04
2

To answer my own question to Hong's answer:

detlist<-c('Hmisc','survival','splines')

lapply(detlist, function(k) detach( paste('package:', k, sep='', collapse=''), unload=TRUE, char=TRUE))

Works just fine. The sorting function at the top of base::detach is a bit wonky, but using character.only=TRUE got me thru just fine.

Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73
1

To delete all currently attached packages:

lapply(names(sessionInfo()$otherPkgs), function(pkgs) detach(paste0('package:',pkgs),character.only = T,unload = T,force=T))
theforestecologist
  • 4,667
  • 5
  • 54
  • 91