40

In R, I'm wondering if it's possible to temporarily redirect the output of the console to a variable?

p.s. There are a few examples on the web on how to use sink() to redirect the output into a filename, but none that I could find showing how to redirect into a variable.

p.p.s. The reason this is useful, in practice, is that I need to print out a portion of the default console output from some of the built-in functions in R.

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
Contango
  • 76,540
  • 58
  • 260
  • 305
  • 2
    You're far, far better off rewriting the functions rather than trying to parse the text they output. – Ari B. Friedman May 03 '13 at 12:07
  • @Ari B. Friedman Unfortunately, that's just not feasible. Currently, all I want to do is chop off some extra line feeds to squeeze the output down to a manageable length. – Contango May 03 '13 at 12:07
  • 2
    @Ben Bolker. Brilliant! This works beautifully. If you add it as an answer, I'll upvote it and mark it as the official answer. – Contango May 03 '13 at 12:09

2 Answers2

41

I believe results <- capture.output(...) is what you need (i.e. using the default file=NULL argument). sink(textConnection("results")); ...; sink() should work as well, but as ?capture.output says, capture.output() is:

Related to ‘sink’ in the same way that ‘with’ is related to ‘attach’.

... which suggests that capture.output() will generally be better since it is more contained (i.e. you don't have to remember to terminate the sink()).

If you want to send the output of multiple statements to a variable you can wrap them in curly brackets {}, but if the block is sufficiently complex it might be better to use sink() (or make your code more modular by wrapping it in functions).

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • 1
    Ben, two notes: 1) `results <- sink()` won't do anything - `sink()` always returns NULL. 2) I don't agree that `capture.output` is better than `sink` - on the contrary, because `sink` allows that the code is not a single function call. Please follow my question: http://stackoverflow.com/q/25781458/684229 – Tomas Sep 11 '14 at 07:24
20

For the record, it's indeed possible to store stdout in a variable with the help of a temorary connection without calling capture.output -- e.g. when you want to save both the results and stdout. Example:

  1. Prepare the variable for the diverted R output:

    > stdout <- vector('character')
    > con    <- textConnection('stdout', 'wr', local = TRUE)
    
  2. Divert the output:

    > sink(con)
    
  3. Do some stuff:

    > 1:10
    
  4. End the diversion:

    > sink()
    
  5. Close the temporary connection:

    > close(con)
    
  6. Check results:

    > stdout
    [1] " [1]  1  2  3  4  5  6  7  8  9 10"
    
daroczig
  • 28,004
  • 7
  • 90
  • 124
  • That was almost what I was looking for. See http://stackoverflow.com/questions/24396806/convert-a-message-to-a-character-vector for how to capture messages while still saving the results – Latrunculia Jun 28 '16 at 10:13
  • @Latrunculia for that goal, I suggest checking `pander::evals` eg at https://cran.rstudio.com/web/packages/pander/vignettes/evals.html – daroczig Jun 29 '16 at 04:25
  • this worked for me to capture messages using sink(`type = "message")`. For some reason I couldn't get `capture.output()` to work. – mikeck Apr 22 '20 at 16:47