system2
system2(command, args = character(), stdout = "", stderr = "", stdin = "", input = NULL, env = character(), wait = TRUE, timeout = 0) character | integer | process · Added in v3.0 · Updated March 24, 2026 · Base Functions Introduction
system2() runs an external command and gives you control over its output streams. Compared to the older system() function, it has cleaner semantics for capturing stdout and stderr separately, handling timeouts, and passing environment variables.
This function lives in base R, so you don’t need to install anything.
Parameters
command (required) The name or path of the command to execute. Must be a single character string.
# Good
system2("ls")
# Bad - will error
system2(c("ls", "ps"))
args A character vector of arguments. Each element becomes a separate argument. Do not pass a single space-separated string.
# Correct - three separate arguments
system2("grep", args = c("-r", "-n", "pattern", "."))
# Wrong - grep will look for a file literally named "-r -n pattern ."
system2("grep", args = "-r -n pattern .")
stdout Controls where stdout goes:
""(default): capture and return as a character vectorFALSE: discard completelyTRUE: send to R’s stdout (prints directly, does not capture)- filename string: write to that file
stderr
Same options as stdout. Note that on Unix systems, when you capture stdout with stdout="", stderr gets merged into it automatically.
stdin Controls stdin input:
""(default): empty stdinTRUE: read from R’s stdin- filename: read input from a file
input
A single character string sent to the command’s stdin. For multi-line input, use stdin=filename instead.
env A named character vector of environment variables to set for the command.
system2("echo", args = "HOME is $HOME", env = c("HOME" = "/tmp"))
# [1] "HOME is /tmp"
wait
TRUE(default): wait for the command to finish before returningFALSE: spawn the process and return immediately (requires R 3.4.0+)
When wait=FALSE, the return value is a process object. Query its exit status with parallel::mcquitest().
minimized and invisible Windows-only parameters. R silently ignores them on other platforms.
timeout
Maximum seconds to wait. 0 means no timeout. On Unix, this uses the timeout(1) command internally. When a command times out, the exit status is 124.
Return Value
The return type depends on your stdout and wait settings:
| stdout | wait | Return value |
|---|---|---|
"" | TRUE | Character vector of stdout lines (or exit status if no output) |
FALSE | TRUE | Exit status integer |
| any | FALSE | Process object |
# Captures output
lines <- system2("ls", args = "-1", stdout = "")
class(lines)
# [1] "character"
# Gets only exit status
status <- system2("grep", args = c("-q", "foo", "bar.txt"), stdout = FALSE)
status
# [1] 1
# Asynchronous - returns immediately
p <- system2("sleep", args = "10", wait = FALSE)
# Process object returned right away
Capturing Command Output
The most common use case is running a command and getting its output back into R.
# List files with details
result <- system2("ls", args = c("-la", tempdir()), stdout = "")
cat(result, sep = "\n")
# [1] "total 32"
# [1] "drwxr-xr-x 6 user user 4096 Mar 24 10:00 ."
# [1] "drwxr-xr-x 5 user user 4096 Mar 24 09:30 ..."
For checking whether a pattern exists in a file, capture the exit status instead of the output:
find_pattern <- function(pattern, file) {
status <- system2("grep", args = c("-q", pattern, file), stdout = FALSE)
status == 0
}
find_pattern("TODO", "README.md")
# [1] FALSE
Handling Timeouts
The timeout parameter kills commands that run too long. Exit status 124 means the timeout fired.
# This will be killed after 2 seconds
result <- system2("sleep", args = "10", timeout = 2, stdout = "")
result
# [1] 124
# Check for timeout
was_timeout <- function(result) {
is.integer(result) && length(result) == 1 && result == 124
}
Be aware that on Unix systems, timeout(1) from GNU coreutils handles the timeout. If your system doesn’t have it, the command runs without a timeout even if you specify one.
Running Commands Asynchronously
Set wait=FALSE to spawn a process and continue immediately. The return value is a process object.
# Spawn a long-running process
p <- system2("python", args = c("-c", "import time; time.sleep(5)"), wait = FALSE)
# Later, check if it finished and get exit status
Sys.sleep(2)
parallel::mcquitest(p)
# Returns exit status when done
This is useful for running multiple commands in parallel, though for complex parallel workloads you might prefer the future or parallel packages.
Common Mistakes
Confusing stdout="" with stdout=FALSE
# Captures output
system2("echo", args = "hello", stdout = "")
# Discards output, returns exit status only
system2("echo", args = "hello", stdout = FALSE)
Passing args as a single string
# Doesn't work as intended
system2("ls", args = "-la ~")
# What you actually get: ls looks for a file literally named "-la ~"
# Correct
system2("ls", args = c("-la", "~"))
Assuming cross-platform interleaving works the same way
# On Unix: both stdout and stderr are merged into result
result <- system2("some_command", stdout = "", stderr = "")
# On Windows: stdout and stderr are kept separate
# There is no simple one-liner to capture interleaved output on both platforms.
Using input for multi-line strings
# input expects a single string
system2("cat", input = "hello world")
# For multiple lines, write to a temp file
writeLines(c("line1", "line2"), "temp.txt")
system2("cat", stdin = "temp.txt", stdout = "")
# [1] "line1" "line2"
unlink("temp.txt")
See Also
- cat — concatenate and print objects
- readline — read a line from the terminal
- print — print R objects
Related Functions
system()— older interface with messier semanticsshell()— Windows-specific command execution