Question

I'm trying to obtain the output from multiple lines of code by storing it into a text variable. To generate the output, I am running code into eval(parse()). Please note, the parse() has been sanitized of 'bad' commands via a blacklist and that users sending code are trusted.

Below works perfectly for capturing the output of ONE function that sends text to the console:

eval(parse(text=
"x=runif(50,0,1);
y=rnorm(50,0,1);
df = data.frame(x=x,y=y);
summary(df);"))
  x                 y           

Min. :0.03062 Min. :-1.86479
1st Qu.:0.27582 1st Qu.:-0.45773
Median :0.52880 Median : 0.03051
Mean :0.50302 Mean : 0.01219
3rd Qu.:0.68359 3rd Qu.: 0.36462
Max. :0.97232 Max. : 3.08798

The above format is perfect for display since it lacks any quotations and terminal line markings (i.e. [1] "..." )

However, if I modify the capture slightly by including a second command that outputs text, I will only receive the output from the last command that generates text:

eval(parse(text="set.seed(200);x=runif(50,0,1);y=rnorm(50,0,1);df = data.frame(x=x,y=y);summary(df);
summary(x);"))
  Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 

0.03062 0.27580 0.52880 0.50300 0.68360 0.97230

One of the ways I've implemented the blacklist is by cycling through the output from parse():

mm=parse(text="set.seed(200);x=runif(50,0,1);y=rnorm(50,0,1);df = data.frame(x=x,y=y);summary(df);
summary(x);")

expression(set.seed(200), x=runif(50,0,1), y=rnorm(50,0,1), df = data.frame(x=x,y=y), summary(df), summary(x))

So, my first instinct to capture multiple commands was to use capture.output(). However, because parse() provides an array of expression()'s, the capture.output() only yields the last eval() except, the output is maligned with additional characters:

capture.output(eval(parse(text="x=runif(50,0,1);
y=rnorm(50,0,1);
plot(x,y);
summary(df);summary(x)")))

[1] " Min. 1st Qu. Median Mean 3rd Qu. Max. " [2] "0.006409 0.218700 0.445300 0.441700 0.635500 0.997800 "

I'm at a loss for where to go from here, any advice would be appreciated.

Was it helpful?

Solution

Make use of the evaluate package.

code = "x=runif(50,0,1);
y=rnorm(50,0,1);
df = data.frame(x=x,y=y);
summary(df);"

replay(evaluate(code))

If you want to save the results to a string,

s = paste(capture.output(replay(evaluate(code))), collapse="\n")
cat(s)

You can save the result returned by evaluate in a list.

code = "x=runif(50,0,1);
y=rnorm(50,0,1);
df = data.frame(x=x,y=y);
summary(df);
summary(x);
"

dont_print_source = function(x){
    if (class(x)!="source"){
        cat(x)
    }
}
L = evaluate(code)
for(i in 1:length(L)) dont_print_source(L[[i]])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top