17

I need to build up long command lines in R and pass them to system(). I find it is very inconvenient to use paste0/paste function, or even sprintf function to build each command line. Is there a simpler way to do like this:

Instead of this hard-to-read-and-too-many-quotes:

cmd <- paste("command", "-a", line$elem1, "-b", line$elem3, "-f", df$Colum5[4])

or:

cmd <- sprintf("command -a %s -b %s -f %s", line$elem1, line$elem3, df$Colum5[4])

Can I have this:

cmd <- buildcommand("command -a %line$elem1 -b %line$elem3 -f %df$Colum5[4]")
ouflak
  • 2,458
  • 10
  • 44
  • 49
biocyberman
  • 5,675
  • 8
  • 38
  • 50
  • 2
    probably [this post](http://stackoverflow.com/questions/10341114/alternative-function-to-paste) will help you – Andriy T. Jun 08 '15 at 13:59
  • IMO just use Python or Bash for this. String manipulation in R is rough – shadowtalker Jun 08 '15 at 14:23
  • @ssdecontrol I already did some commands with IO operations in R. They also use some R packages, so I want to do the rest in R. But you are right, one should not use R for everything. – biocyberman Jun 08 '15 at 19:34

6 Answers6

47

For a tidyverse solution see https://github.com/tidyverse/glue. Example

name="Foo Bar"
glue::glue("How do you do, {name}?")
Holger Brandl
  • 10,634
  • 3
  • 64
  • 63
13

With version 1.1.0 (CRAN release on 2016-08-19), the stringr package has gained a string interpolation function str_interp() which is an alternative to the gsubfn package.

# sample data
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)

# do the string interpolation
stringr::str_interp("command -a ${line$elem1} -b ${line$elem3} -f ${df$Colum5[4]}")
#[1] "command -a 10 -b 30 -f 4"
Community
  • 1
  • 1
Uwe
  • 41,420
  • 11
  • 90
  • 134
  • 1
    This has the downside that if you need to interpolate by key-value like in this case, the list needs to have all elements available at once and then interpolate them in one go, you can't interpolate one after the other, which could be useful in different scenarios. – intael Jan 07 '20 at 11:12
  • @intael Thank you for your feedback but I do not understand what you are after and why you have picked and downvoted only this answer. (1) This answer is similar to the other ones which use interpolation with different tools. (2) It does what the user has asked for - no more and no less. – Uwe Jan 07 '20 at 15:55
11

This comes pretty close to what you are asking for. When any function f is prefaced with fn$, i.e. fn$f, character interpolation will be performed replacing ... with the result of running ... as an R expression.

library(gsubfn)
cmd <- fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")

Here is a self contained reproducible example:

library(gsubfn)

# test inputs
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)

fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## [1] "command -a 10 -b 30 -f 4"

system

Since any function can be used we could operate directly on the system call like this. We have used echo here to make it executable but any command could be used.

exitcode <- fn$system("echo -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## -a 10 -b 30 -f 4

Variation

This variation would also work. fn$f also performs substitution of $whatever with the value of variable whatever. See ?fn for details.

with(line, fn$identity("command -a $elem1 -b $elem3 -f `df$Colum5[4]`"))
## [1] "command -a 10 -b 30 -f 4"
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

Another option would be to use whisker.render from https://github.com/edwindj/whisker which is a {{Mustache}} implementation in R. Usage example:

require(dplyr); require(whisker)

bedFile="test.bed"
whisker.render("processing {{bedFile}}") %>% print
Holger Brandl
  • 10,634
  • 3
  • 64
  • 63
0

Not really a string interpolation solution, but still a very good option for the problem is to use the processx package instead of system() and then you don't need to quote anything.

Gabor Csardi
  • 10,705
  • 1
  • 36
  • 53
-1
library(GetoptLong)

str = qq("region = (@{region[1]}, @{region[2]}), value = @{value}, name = '@{name}'")
cat(str)

qqcat("region = (@{region[1]}, @{region[2]}), value = @{value}, name = '@{name}'")

https://cran.r-project.org/web/packages/GetoptLong/vignettes/variable_interpolation.html

  • Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation would greatly improve its long-term value](//meta.stackexchange.com/q/114762/206345) by showing _why_ this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – Blue Nov 08 '18 at 03:59