35

In base R, there are 3 main mechanisms for invoking a system command: system, system2, and shell (which seems to share a manpage with system). None of them provide a very reliable cross-platform way to run a system command without a shell getting in the way - and if a shell intervenes, we need to worry about shell injection attacks, about making sure the quoting is correct, and so on.

Some languages provide direct access to the C-level execvp function (e.g. Perl's system PROGRAM LIST mechanism), which is extremely helpful when I want to make sure that the strings in an array are exactly the strings the subprocess will see in its arguments, without looking around for the appropriate quoting routine for embedded whitespace, quotes, etc. and worrying about what they'll do on different platforms and different versions of shells.

Is there a similar no-shell system-call mechanism available in R, perhaps in a CRAN package somewhere? And/or is there any appetite for creating such a mechanism if there isn't one already?

keen
  • 756
  • 9
  • 10
Ken Williams
  • 19,823
  • 7
  • 71
  • 126
  • Very interesting question, and I'd like to know the answer. However, as it stands, the question can possibly be interpreted as either asking for a tool (off topic) or primarily opinion-based. I'm not going to vote to close, but perhaps you can apply a bit of editing to avoid these outcomes? – Andrie Nov 05 '14 at 21:44
  • @Andrie isn't the first question in the last paragraph enough ? – Paulo E. Cardoso Nov 05 '14 at 21:53
  • @PauloCardoso, as Andrie points out, the first question in the last paragraph *is* "asking for a tool". I imagine it would be easy to write a package with a trivial piece of code that just passed a string to `execvp` ... – Ben Bolker Nov 05 '14 at 22:55
  • 1
    @BenBolker - it wouldn't pass a string, it would pass a vector (array) of strings, but yes, conceptually easy. If one already exists though, it wouldn't be the first time I've overlooked a useful tool. – Ken Williams Nov 06 '14 at 04:43
  • 2
    @Andrie - perhaps if I worded it more simply as "how do I make a system call without invoking the shell?" it would fit the guidelines better, but really the question is the same, and I'm just trying to give more background on what I mean & why I'd want it. – Ken Williams Nov 06 '14 at 04:47
  • 1
    No, `system2` has the same problem. If you look at its source, the first thing it does is `command – Ken Williams Sep 02 '15 at 16:16

2 Answers2

1

The following code runs a command in R without shell interaction:

library(inline)
cfun <- cfunction(sig = signature(),
          includes = "#include <unistd.h>",
body = 'execl("/bin/date", "date", 0, 0, (char *)0);')
cfun()

I'm pretty sure this is a bad idea, as I think it would terminate the R process upon completion of the executed process. What about fork?

The base package parallel C function mc_fork use the C system command fork to achieve this, with pipes for inter-process communication. I do not know how this would fly on Windows with MinGW, but since it is in a base package, it would seem likely to work, although perhaps with a very different downstream mechanism.

In the R sources for parallel I see in R-devel/src/library/parallel/src/fork.c

SEXP mc_fork(SEXP sEstranged)
...
pid = fork();
Jack Wasey
  • 2,998
  • 18
  • 41
0

Expanding on @Jack Wasey's intuition:

library(inline)
cfun <- cfunction(sig = signature(),
          includes = "#include <unistd.h>",
body = '
pid_t fk = fork();
if (!fk) {
    execl("/bin/date", "date", 0, 0, (char *)0);
} else if (fk == -1) {
    perror("fork");
}
return(R_NilValue);
')
cfun()

... uses fork to prevent the hijacking of the current process (at least in Linux), but returns you safely to R with nothing to show for it.

russellpierce
  • 4,206
  • 2
  • 29
  • 41