system2

system2(command, args = character(), stdout = "", stderr = "", stdin = "", input = NULL, env = character(), wait = TRUE, timeout = 0)
Returns: character | integer | process · Added in v3.0 · Updated March 24, 2026 · Base Functions
r system external-commands process

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 vector
  • FALSE: discard completely
  • TRUE: 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 stdin
  • TRUE: 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 returning
  • FALSE: 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:

stdoutwaitReturn value
""TRUECharacter vector of stdout lines (or exit status if no output)
FALSETRUEExit status integer
anyFALSEProcess 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
  • system() — older interface with messier semantics
  • shell() — Windows-specific command execution