user1424739
user1424739

Reputation: 13675

How to escape bash code so that it can be run by `system()`?

R> system('bash -c "cat <(seq 3)"', intern=T)
[1] "1" "2" "3"

If I use any bash-specific features, I will have to manually call bash -c. But that means I will have to properly escape it so that it can be embedded in a string. For example, I can manually escape the bash code like this.

R> system('bash -c "cat <(printf \'%s\\n\' {a..c})"', intern=T)
[1] "a" "b" "c"

But how to automate the escape process robustly, so that it will work on arbitrary bash code.

Essentially, I want to have a function that can turn any legal bash command string (e.g., cat <(printf '%s\n' "'" {a..c})) into a string runable by system(). Note the requirement of robustness, it must work with any arbitrary legal bash command.

EDIT: It seems that if printf %q from bash can be implemented in R, this problem may be solved? If so, how to implement it?

Upvotes: 0

Views: 131

Answers (1)

Mikael Jagan
Mikael Jagan

Reputation: 11316

To avoid manually inserting escapes in system commands, you can construct the commands using shQuote, possibly recursively. shQuote wraps its argument (a string) in single or double quotes depending on its content, inserting escapes as necessary, and returns the result. sprintf and paste are often useful here:

cmd_bash <- sprintf("cat <(printf %s %s %s)", shQuote("%s\n"), shQuote("'"), "{a..c}")
cmd_bash
## [1] "cat <(printf '%s\n' \"'\" {a..c})"

cmd <- paste("bash -c", shQuote(cmd_bash))
cmd
## [1] "bash -c \"cat <(printf '%s\n' \\\"'\\\" {a..c})\""

system(cmd, intern = TRUE)
## [1] "'" "a" "b" "c"

FWIW, you can read from stdin interactively with readLines, using ControlD to signal EOF and/or argument n to signal EOF after n lines have been entered:

zzz <- readLines(stdin())
## '
## a
## b
## c
## ^D

zzz
## [1] "'" "a" "b" "c"

zzz <- readLines(stdin(), n = 4L)
## '
## a
## b
## c

zzz
## [1] "'" "a" "b" "c"

zzz <- system(paste("bash -c", shQuote(readLines(stdin(), n = 1L))), intern = TRUE)
## cat <(printf '%s\n' "'" {a..c})

zzz
## [1] "'" "a" "b" "c"

In the last example, the Bash command was typed as if at a Bash prompt, in the running R process.

Upvotes: 1

Related Questions