Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

R (4.6)  Module 1 – Start here: R, the console and a working setup

Scripts, projects and file paths that travel

Organise an R analysis as a project folder, run scripts with source() and Rscript, pass arguments, build portable paths and list files with fixed patterns.

  • Beginner
  • 15 minutes
  • Examples run with R 4.6.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Organise an analysis as a project folder with raw data, scripts and outputs kept apart
  • Run a script with source() and with Rscript, and read its command-line arguments
  • Build portable paths with file.path() and relative paths instead of setwd()
  • List and test files with list.files(), file.exists() and fixed patterns
  • Use Sys.getenv() and system2() to read settings and run other programs

Before you start

What you’ll learn · Before you start

What you will learn

  • Organise an analysis as a project folder with raw data, scripts and outputs kept apart
  • Run a script with source() and with Rscript, and read its command-line arguments
  • Build portable paths with file.path() and relative paths instead of setwd()
  • List and test files with list.files(), file.exists() and fixed patterns
  • Use Sys.getenv() and system2() to read settings and run other programs

Before you start

On this page

A script that starts with setwd("C:/Users/asha/Desktop/survey") runs on one computer only. On every other one it stops on its first line with “cannot change working directory”, before it has read a single row. The fix is a habit rather than a tool: one folder per analysis, every path relative to that folder, and scripts that run from their first line to their last on their own.

Below you lay out a project folder, run scripts with source() and with Rscript and give them arguments, build paths that work on Windows, macOS and Linux, list files without being caught out by a regular expression, and read settings from the environment instead of writing them into the code.

A project folder keeps raw data, scripts and output apart

Put everything one analysis needs in one folder, and give each kind of file its own place inside it. Follow the data of a small clinic-visits analysis through such a folder:

Interactive · step by step One analysis, one folder Step through the project folder of a clinic-visits analysis and follow the data from the raw file to the output.
One analysis, one folder, step 6 of 6. Showing data/raw/visits.csv, R/01-clean.R, data/clean/visits.csv, R/02-analyse.R, output/, README.txt. In focus: README.txt.readwritereadwritedata/raw/visits.csvas it arrivedR/01-clean.Rreads raw, writes cleandata/clean/visits.csvmade only by a scriptR/02-analyse.Rreads clean data onlyoutput/tables and figuresREADME.txthow to rerun it

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Raw data, untouched. The raw file goes into data/raw exactly as it arrived, and nothing ever edits it there. If a later step turns out wrong, you can always start again from it.
  2. A script reads it. R/01-clean.R reads the raw file. Scripts live in R/, numbered in the order they run.
  3. Cleaned data, by script. It writes the cleaned table to data/clean. A cleaned file is not edited by hand either; to change it, change the script and run it again.
  4. The analysis reads clean data. R/02-analyse.R reads only the clean data, so every number it computes leads back to the raw file through code.
  5. Output can be made again. Tables and figures go to output/. Delete output/ and data/clean/, and running the two scripts makes them again.
  6. Everything in one folder. README.txt says where the raw data came from and which script runs first. A colleague who copies the folder needs nothing from your computer.

The rule behind the layout is that data only ever changes by running code. Raw data stays as it arrived, cleaned data and output are made by scripts, and so anyone can delete them and make them again. This script creates the folders, with a raw file and a README, and lists what it made:

A project folder, made by a script R · project_skeleton.R
# One folder per analysis: raw data, cleaned data, scripts and output apart.
project <- "clinic-visits"
for (part in c("data/raw", "data/clean", "R", "output")) {
  dir.create(file.path(project, part), recursive = TRUE)
}
writeLines(
  c("site,visits", "north,12", "south,7"),
  file.path(project, "data", "raw", "visits.csv")
)
writeLines("Where the data came from, and when.", file.path(project, "README.txt"))

# Every folder and file of the project, relative to its top folder.
list.files(project, recursive = TRUE, include.dirs = TRUE)
project_skeleton.R, run with R 4.6.1 Python · project_skeleton_session.py
from session import run, version

version()
run("""
Rscript project_skeleton.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ Rscript project_skeleton.R
[1] "data"                "data/clean"          "data/raw"           
[4] "data/raw/visits.csv" "output"              "R"                  
[7] "README.txt"         

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 project_skeleton_session.py

list.files(project, recursive = TRUE, include.dirs = TRUE) lists every folder and file under clinic-visits, as paths relative to it: data/raw/visits.csv is a path from the project’s top folder, which is the point of the layout.

Scripts find these files from the working directory: The folder that relative paths start from. getwd() shows it; opening a project in RStudio, or starting R or Rscript in a folder, sets it., the folder that relative paths start from. Opening a project in RStudio sets the working directory to the project’s folder and starts a new R session; from a terminal, start R or Rscript in the project’s top folder. Two more habits keep an analysis honest:

  • Restart R often, and do not save the workspace. At the end of a session R offers to save every object into a file called .RData, and the next R started in that folder loads it again by itself. Objects that come back that way, rather than from your scripts, make results that no script can reproduce. Answer no, or start R with --no-save.
  • Name files plainly. The tidyverse style guide asks for .R file names in lower case, with words joined by - or _ and no spaces or symbols, so that they work in every system’s paths.

Key idea

Keep raw data untouched and let scripts make everything else, inside one folder whose paths all start from its top: a colleague who copies the folder can then rerun the whole analysis.

Checkpoint

Check: A project folder for one analysis

  1. Question 1 of 2 In the project layout, where does the data file go exactly as it arrived?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: data/raw, where nothing ever edits it

    Data changes only by running code: raw data in data/raw, cleaned data in data/clean, results in output/, scripts in R/, and a README that says how to rerun it.

  2. Question 2 of 2 When you quit, R offers to save the workspace to a file called .RData. Why answer no?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Objects that come back from .RData, not from your scripts, can make results that no script reproduces

    Restart R often and do not save the workspace, so that every object of an analysis comes from a script you can run again.

source() runs a script in your session; Rscript runs it on its own

There are two ways to run a script, and they differ in where the results end up. source("file.R") runs every line of the file in your current session, and what the script makes stays in your workspace. Rscript: The program that runs an R script from a terminal in a new R session, which ends with the script. Words after the file name reach commandArgs(). runs the file in a new R session, which ends when the script ends. This script reads the visits and keeps their total:

R/count_sites.R R · R/count_sites.R
# Reads the raw visits and keeps their total in total_visits.
visits <- read.csv(file.path("data", "raw", "visits.csv"))
total_visits <- sum(visits$visits)

The session below sources it at the console, then runs the same file with Rscript, then asks a new R whether the total exists:

source() and Rscript, with R 4.6.1 Python · source_session.py
from session import run, version

version()
# source() inside a console session, then the same script run on its own with Rscript, then a new R that looks for
# what the script made.
run("""
R --vanilla --quiet -f source_demo.R
Rscript R/count_sites.R
Rscript -e 'exists("total_visits")'
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f source_demo.R
> # source() runs every line of a script in this session.
> source(file.path("R", "count_sites.R"))
> # What the script made stays in the workspace.
> total_visits
[1] 43
> ls()
[1] "total_visits" "visits"      
$ Rscript R/count_sites.R
$ Rscript -e 'exists("total_visits")'
[1] FALSE

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 source_session.py

After source() the workspace holds total_visits, 43, and visits. Rscript R/count_sites.R prints nothing, because the script has only assignments, and leaves nothing behind: the new R answers FALSE. Use source() while you work on an analysis, and Rscript for runs that must not depend on anything in your session, such as the final run of a report.

A script run by Rscript can take command-line argument: A word typed after a script's name when it is run, such as 10 in Rscript summarise.R data.csv 10. R receives every argument as text., words after its file name, which commandArgs(trailingOnly = TRUE) returns. Step through a run of summarise.R, which keeps the sites with at least a given number of visits:

Interactive · message by message A script with arguments, run by Rscript Step through one run of summarise.R with two arguments, then a run with a bad one, and watch what reaches R and what comes back.
A script with arguments, run by Rscript, step 7 of 7. Messages so far: Terminal to Rscript: summarise.R …/visits.csv 10; Rscript to Project files: read.csv(path); Rscript to Project files: busy-sites-10.csv; Rscript to Terminal: exit status 0; Rscript to Terminal: exit status 1.TerminalRscriptstopped: not a numberProject filesdata/ and output/summarise.R …/visits.csv 10read.csv(path)busy-sites-10.csvexit status 0exit status 1

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. The command. You type Rscript summarise.R data/raw/visits.csv 10 in a terminal, in the project's top folder. Rscript starts a new R session with an empty workspace.
  2. The arguments are text. commandArgs(trailingOnly = TRUE) returns the words after the script's name, "data/raw/visits.csv" and "10". Both are text, as str(args) printed.
  3. Checked and converted. as.numeric() turns "10" into the number 10. The script stops at once if that fails, or if the file does not exist.
  4. Read the data. The script reads the four sites from the path it was given, which is relative to the working directory, the project's top folder.
  5. Write the result. It writes the two sites with at least 10 visits to output/busy-sites-10.csv and prints a line about it.
  6. Exit status 0. The session ends, and its workspace with it. Rscript exits with status 0, success. Only the files remain.
  7. A bad argument. With ten instead of 10, as.numeric() gives NA, so the script calls stop() with a message, and Rscript exits with status 1, which tells a scheduler or another script that the run failed.

summarise.R: a script with two arguments R · summarise.R
# Usage: Rscript summarise.R <csv file> <minimum visits>
args <- commandArgs(trailingOnly = TRUE)
str(args)
if (length(args) != 2) {
  stop("give a CSV file and a minimum number of visits")
}
path <- args[1]
minimum <- suppressWarnings(as.numeric(args[2]))
if (is.na(minimum)) stop("the minimum must be a number, not ", sQuote(args[2]))
if (!file.exists(path)) stop("there is no file ", path)

visits <- read.csv(path)
busy <- visits[visits$visits >= minimum, ]
dir.create("output", showWarnings = FALSE)
out <- file.path("output", paste0("busy-sites-", minimum, ".csv"))
write.csv(busy, out, row.names = FALSE)
cat("Read", nrow(visits), "sites; wrote", nrow(busy), "with at least", minimum, "visits to", out, "\n")
summarise.R, run with Rscript and R 4.6.1 Python · summarise_session.py
from session import run, version

version()
# Two good runs, the file the first one wrote, then two runs that the script stops on purpose.
run("""
Rscript summarise.R data/raw/visits.csv 10
cat output/busy-sites-10.csv
Rscript summarise.R data/raw/visits.csv 8
!Rscript summarise.R data/raw/visits.csv ten
!Rscript summarise.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ Rscript summarise.R data/raw/visits.csv 10
 chr [1:2] "data/raw/visits.csv" "10"
Read 4 sites; wrote 2 with at least 10 visits to output/busy-sites-10.csv 
$ cat output/busy-sites-10.csv
"site","visits"
"north",12
"east",15
$ Rscript summarise.R data/raw/visits.csv 8
 chr [1:2] "data/raw/visits.csv" "8"
Read 4 sites; wrote 3 with at least 8 visits to output/busy-sites-8.csv 
$ Rscript summarise.R data/raw/visits.csv ten
 chr [1:2] "data/raw/visits.csv" "ten"
Error: the minimum must be a number, not ‘ten’
Execution halted
[exit status 1]
$ Rscript summarise.R
 chr(0) 
Error: give a CSV file and a minimum number of visits
Execution halted
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 summarise_session.py

The first run kept the 2 sites with at least 10 visits, north and east, and the second the 3 with at least 8. With ten, and with no arguments at all, the script stopped on purpose with a message that says what is wrong, and Rscript exited with status 1, which tells a scheduler or another script that the run failed.

Comparing arguments while they are still text

Every command-line argument is text: str(args) printed chr [1:2]. Compared as text, "10" >= "9" is FALSE, because the character 1 sorts before 9. Convert first, as.numeric(args[2]), check the result for NA, and only then compare.

Checkpoint

Check: source(), Rscript and arguments

  1. Question 1 of 2 After Rscript R/count_sites.R, a new R answers FALSE to exists("total_visits"). Why?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Rscript ran the script in a session of its own, which ended with the script and kept nothing

    source() runs a script in your session and leaves its objects there; Rscript runs it in a new session, which keeps nothing when it ends.

  2. Question 2 of 2 A script compares its second command-line argument, "10", with 9 without converting it. What does this print?

    Read the code, then choose one answer.

    "10" >= "9"
    Show the answer: Question 2 of 2

    Answer: [1] FALSE

    commandArgs() returns text, so convert with as.numeric(), check for NA, then compare: as.numeric("10") >= 9 is TRUE.

Paths that work on every computer

A path written as one piece of text, "data\\raw\\visits.csv" or "/Users/asha/survey/data.csv", carries the habits of one system or the folders of one person. Build paths from their parts instead, relative to the project’s top folder:

paths.R, typed at the R console Python · paths_session.py
from session import run, version

version()
run("""
R --vanilla --quiet -f paths.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f paths.R
> # file.path() joins the parts with "/", which R also accepts on Windows.
> raw <- file.path("data", "raw", "visits.csv")
> raw
[1] "data/raw/visits.csv"
> # Take a path apart without cutting text by hand.
> basename(raw)
[1] "visits.csv"
> dirname(raw)
[1] "data/raw"
> tools::file_ext(raw)
[1] "csv"
> tools::file_path_sans_ext(basename(raw))
[1] "visits"
> # A relative path starts from the working directory.
> file.exists(raw)
[1] TRUE
> file.exists(file.path("data", "raw", "missing.csv"))
[1] FALSE

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 paths_session.py

file.path() joins the parts with /, and its help page notes that /, not \, is the separator it uses on Windows too, so the same line works everywhere. The other functions take a path apart without any cutting of text:

Function On data/raw/visits.csv it gives
basename() visits.csv, the last part
dirname() data/raw, everything before it
tools::file_ext() csv, the extension without its dot
tools::file_path_sans_ext() the path without its extension
file.exists() TRUE or FALSE for each path

A relative path: A path that starts from the working directory, such as data/raw/visits.csv, rather than from the top of the disk. such as data/raw/visits.csv starts from the working directory, so it works on any computer as long as R starts in the project’s top folder. The here package, on CRAN, goes one step further: it builds paths from a project’s top folder wherever a script runs, and its documentation calls setwd() “fragile and dependent on the way you organize your files”.

setwd() with a folder of your own computer

setwd("C:/Users/asha/Desktop/survey") at the top of a script fails on every other computer with “cannot change working directory”, and on yours once the folder moves. Start R in the project’s folder instead, and write paths as file.path("data", "raw", "visits.csv").

Checkpoint

Check: Paths that work on every computer

  1. Question 1 of 2 What does this line print?

    Read the code, then choose one answer.

    file.path("data", "raw", "visits.csv")
    Show the answer: Question 1 of 2

    Answer: [1] "data/raw/visits.csv"

    The recorded run printed "data/raw/visits.csv". The same line works on Windows, macOS and Linux.

  2. Question 2 of 2 A colleague copies your project and runs read.csv(file.path("data", "raw", "visits.csv")). When does it work?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: When their R's working directory is the project's top folder

    Opening the project in RStudio, or running Rscript in a terminal in the project's top folder, makes that folder the working directory.

list.files() matches a regular expression unless you ask for fixed

list.files() lists the files of a folder, sorted alphabetically, and its pattern argument picks some of them. pattern is a regular expression: A pattern language for text, in which . matches any character, ^ the start and $ the end. list.files() reads its pattern argument as one., not plain text, and that catches people out. Here are five file names and four ways to ask for the CSV files:

list_files.R, typed at the R console Python · list_files_session.py
from session import run, version

version()
run("""
R --vanilla --quiet -f list_files.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f list_files.R
> # Five files in a folder called inbox.
> files <- c("visits.csv", "visits.csv.bak", "visits_csv.txt", "old-visits.csv", "notes.txt")
> dir.create("inbox")
> invisible(file.create(file.path("inbox", files)))
> # pattern is a regular expression, in which "." matches any character.
> list.files("inbox", pattern = "visits.csv")
[1] "old-visits.csv" "visits_csv.txt" "visits.csv"     "visits.csv.bak"
> # Escape the dot and anchor the end: only names that end in .csv.
> list.files("inbox", pattern = "\\.csv$")
[1] "old-visits.csv" "visits.csv"    
> # fixed = TRUE, new in R 4.6.0, matches the text exactly as written.
> list.files("inbox", pattern = "visits.csv", fixed = TRUE)
[1] "old-visits.csv" "visits.csv"     "visits.csv.bak"
> # full.names = TRUE gives paths you can open.
> list.files("inbox", pattern = "\\.csv$", full.names = TRUE)
[1] "inbox/old-visits.csv" "inbox/visits.csv"    

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 list_files_session.py

In a regular expression . matches any character, and a pattern may match anywhere in a name. So pattern = "visits.csv" also matched visits_csv.txt, through its underscore, and visits.csv.bak, which merely contains the text. Two fixes, for two needs:

  • A pattern that means what it says: "\\.csv$", with the dot escaped as \\. and $ for the end of the name, lists only the names that end in .csv.
  • Plain text: fixed = TRUE, an argument new in R 4.6.0, matches the pattern exactly as written. It no longer matched visits_csv.txt, but it still matched visits.csv.bak, which contains the text.

full.names = TRUE adds the folder to each name, giving paths you can open, and recursive = TRUE looks inside subfolders, as the project skeleton did.

Checkpoint

Check: Listing files with patterns

  1. Question 1 of 2 Why did list.files("inbox", pattern = "visits.csv") list visits_csv.txt?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: pattern is a regular expression, in which the dot matches any character, here the underscore

    Escape the dot, "\\.csv$", or use fixed = TRUE, new in R 4.6.0, to match the text as written.

  2. Question 2 of 2 Which call lists exactly the names in inbox that end in .csv?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: list.files("inbox", pattern = "\\.csv$")

    The run listed old-visits.csv and visits.csv for "\\.csv$". fixed = TRUE is the choice when the pattern is plain text that may appear anywhere in a name.

Settings and other programs: Sys.getenv() and system2()

A script should not change from one computer to the next, but some settings do: a folder outside the project, a threshold that differs between runs, a password. Read them from environment variable: A named setting that the operating system passes to the programs it starts. R reads one with Sys.getenv() and always gets text., which the system or the person running the script sets, and run other programs with system2():

settings.R, typed at the R console Python · settings_session.py
from session import run, version

version()
run("""
R --vanilla --quiet -f settings.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f settings.R
> # Sys.getenv() reads an environment variable; unset is the value when it is missing.
> Sys.getenv("CLINIC_MIN_VISITS", unset = "10")
[1] "10"
> # Set it for this session, then read it again.
> Sys.setenv(CLINIC_MIN_VISITS = "8")
> as.numeric(Sys.getenv("CLINIC_MIN_VISITS"))
[1] 8
> # system2() runs another program; stdout = TRUE returns what it printed.
> system2("Rscript", c("-e", shQuote("cat(6 * 7)")), stdout = TRUE)
[1] "42"

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 settings_session.py

Sys.getenv("CLINIC_MIN_VISITS", unset = "10") returned "10" because the variable was not set; after Sys.setenv() it returned "8", text again, which as.numeric() turns into a number. system2() ran a second R, and with stdout = TRUE it returned what that program printed as text, "42".

Sys.setenv() lasts for the current R session and the programs it starts, and changes nothing outside them. To set a variable for every session, write a line such as CLINIC_MIN_VISITS=8 in a file called .Renviron, which R reads when it starts, from the current folder or else from your home folder. R --vanilla skips that file, and a .Renviron that holds a secret stays out of version control.

Keep passwords and tokens out of scripts

A script is shared, copied and kept in version control, so a password written into it travels with it. Read it with Sys.getenv("SURVEY_API_TOKEN"), which returns an empty string when it is not set, and stop the script with a message when it is empty.

Checkpoint

Check: Environment variables and other programs

  1. One question In a fresh session where nothing set it, what does Sys.getenv("CLINIC_MIN_VISITS", unset = "10") return?

    Choose one answer.

    Show the answer: One question

    Answer: The text "10"

    The recorded run printed [1] "10", and after Sys.setenv(CLINIC_MIN_VISITS = "8"), as.numeric() of the value printed 8.

Practise: a project that runs anywhere

Build a small project on your own computer, in order:

  1. Make a folder called clinic-visits with data/raw, data/clean, R and output inside it, and put a short CSV file of sites and visits into data/raw.
  2. Write R/summarise.R like the script above, with file.path() for every path and no setwd().
  3. In a terminal in the project’s top folder, run Rscript R/summarise.R data/raw/visits.csv 10, then with ten and check that it stops with your message.
  4. Copy the folder somewhere else, run the same command there, and compare the files in output.

Finally, the self-check covers projects, scripts, paths, file patterns and settings. It picks the idea you are least sure of, explains every answer as soon as you give it, and ends with a summary that links each idea to the part to reread:

Practice that adapts to you

Practise this lesson

16 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 16 Why may you delete data/clean and output in this layout?

    Choose one answer.

    Show the answer: Question 1 of 16

    Answer: The scripts make them from the raw data, so running the scripts makes them again

    A folder from which data/clean and output can be deleted and rebuilt by its scripts is a folder whose results can be checked.

  2. Question 2 of 16 What belongs in the project's README.txt?

    Choose one answer.

    Show the answer: Question 2 of 16

    Answer: Where the raw data came from, and which script runs first

    The README is the first thing a colleague reads: where the data came from, what to install and which command reruns everything.

  3. Question 3 of 16 You find a wrong value in data/clean/visits.csv. What is the right fix?

    Choose one answer.

    Show the answer: Question 3 of 16

    Answer: Fix the cleaning script, so the correction is in code, and run it again

    Data changes only by running code. A correction belongs in the script, with a comment saying why.

  4. Question 4 of 16 Which command runs analysis.R on its own, from a terminal?

    Choose one answer.

    Show the answer: Question 4 of 16

    Answer: Rscript analysis.R

    Rscript is the scripting front end of R. Inside R, source("analysis.R") runs the same file in the current session.

  5. Question 5 of 16 A script is run with Rscript report.R north 12. What does commandArgs(trailingOnly = TRUE) return inside it?

    Read the code, then choose one answer.

    commandArgs(trailingOnly = TRUE)
    Show the answer: Question 5 of 16

    Answer: [1] "north" "12"

    Arguments are always text. Convert "12" with as.numeric() and check the result before using it.

  6. Question 6 of 16 A scheduler runs Rscript summarise.R data/raw/visits.csv 10 every night. How can it tell that a run failed?

    Choose one answer.

    Show the answer: Question 6 of 16

    Answer: Rscript exits with a status other than 0 when the script stops with an error

    stop() with a clear message makes a script fail early and loudly: the message goes to the log, and the exit status 1 goes to whatever started the run.

  7. Question 7 of 16 What does this line print?

    Read the code, then choose one answer.

    basename("data/raw/visits.csv")
    Show the answer: Question 7 of 16

    Answer: [1] "visits.csv"

    basename(), dirname(), tools::file_ext() and tools::file_path_sans_ext() take a path apart, as the recorded run showed for data/raw/visits.csv.

  8. Question 8 of 16 What does this line print?

    Read the code, then choose one answer.

    tools::file_path_sans_ext(basename("output/busy-sites-10.csv"))
    Show the answer: Question 8 of 16

    Answer: [1] "busy-sites-10"

    The inner call runs first: basename() gives busy-sites-10.csv, then file_path_sans_ext() drops .csv.

  9. Question 9 of 16 A script you receive starts with setwd("C:/Users/ravi/project"). What do you change so that it runs on your computer and on every other?

    Choose one answer.

    Show the answer: Question 9 of 16

    Answer: Remove the line, start R in the project's top folder, and build paths from there with file.path()

    setwd() with an absolute path ties a script to one computer. The working directory should be the project's top folder, set by how R is started, not by the script.

  10. Question 10 of 16 In what order does list.files() return the names?

    Choose one answer.

    Show the answer: Question 10 of 16

    Answer: Sorted alphabetically

    The recorded runs came back sorted. The exact order of letters, digits and symbols follows the system's language settings.

  11. Question 11 of 16 Which argument makes list.files() return paths you can pass straight to read.csv()?

    Choose one answer.

    Show the answer: Question 11 of 16

    Answer: full.names = TRUE

    Without full.names, list.files() returns names relative to the folder it listed, which read.csv() cannot find from the project's top folder.

  12. Question 12 of 16 Since which R version does list.files() have the fixed argument?

    Choose one answer.

    Show the answer: Question 12 of 16

    Answer: R 4.6.0

    On R older than 4.6.0, escape the pattern instead: "\\.csv$". A script that uses fixed = TRUE needs R 4.6.0 or later.

  13. Question 13 of 16 A folder holds report.csv, report.csv.old and report_csv_notes.txt. Which pattern lists report.csv alone?

    Choose one answer.

    Show the answer: Question 13 of 16

    Answer: "^report\\.csv$"

    Anchor both ends when you mean one exact name: ^ for the start, $ for the end, and an escaped dot inside.

  14. Question 14 of 16 What happens here?

    Read the code, then choose one answer.

    Sys.setenv(N = "8")
    Sys.getenv("N") + 1
    Show the answer: Question 14 of 16

    Answer: An error, because Sys.getenv() returns text, and text cannot be added to

    Convert values from the environment, as the recorded run did with as.numeric(Sys.getenv("CLINIC_MIN_VISITS")).

  15. Question 15 of 16 What does system2("Rscript", c("-e", shQuote("cat(6 * 7)")), stdout = TRUE) return?

    Choose one answer.

    Show the answer: Question 15 of 16

    Answer: The text "42", what the other program printed

    The recorded run printed [1] "42". Without stdout = TRUE, the output goes to the console and system2() returns the exit status.

  16. Question 16 of 16 A script needs an API token to download survey data. Where does the token belong?

    Choose one answer.

    Show the answer: Question 16 of 16

    Answer: In an environment variable, read with Sys.getenv(), with a stop() and a message when it is empty

    Settings that differ between computers, and secrets above all, come from the environment; the code stays the same everywhere.

Interview questions

Warm-up: why should an analysis script not call setwd() with an absolute path?

Because the path exists only on the computer where the script was written. setwd("C:/Users/asha/Desktop/survey") stops with “cannot change working directory” on every other computer, before any work is done, and on the same computer it breaks as soon as the folder moves or is renamed. It also hides an assumption: every relative path after it depends on that one line. The portable way is to start R in the project’s top folder, which opening an RStudio project does and a terminal does when you run Rscript there, and to build every path from the project’s top with file.path(). The here package goes one step further and finds the project’s top folder wherever the script runs. setwd() is still fine at the console for a quick look, as long as no script depends on it.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    An analysis script runs every time from your editor, but when a scheduler runs it at night with Rscript it stops with "cannot open the connection" and a warning that it cannot open data/raw/visits.csv. List the likely causes, how you would find the real one, and how you make the script run the same both ways.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    You are leaving a project, and next month a colleague must rerun your analysis from the raw data on another computer, without you. What do you put in the project folder, what do you leave out, and how does your colleague check that the rerun matches your results?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • One folder per analysis keeps raw data untouched in data/raw, scripts in R/ and everything they make in data/clean and output, so a copy of the folder can rerun the whole analysis.
  • source() runs a script in your session and leaves its objects in your workspace; Rscript runs it in a new session that keeps nothing, and exits with status 1 when the script stops with an error.
  • commandArgs(trailingOnly = TRUE) returns a script’s arguments as text, which must be converted and checked before they are used.
  • file.path() and relative paths from the project’s top folder work on every system, and basename(), dirname() and tools::file_ext() take paths apart, where setwd() with an absolute path breaks on the next computer.
  • list.files(pattern = ) reads a regular expression, in which . matches any character; anchor and escape it, or use fixed = TRUE from R 4.6.0.
  • Sys.getenv() reads settings and secrets from the environment, and system2() runs another program and can return what it printed.

Terms in this lesson

command-line argument
A word typed after a script's name when it is run, such as 10 in Rscript summarise.R data.csv 10. R receives every argument as text.
environment variable
A named setting that the operating system passes to the programs it starts. R reads one with Sys.getenv() and always gets text.
regular expression
A pattern language for text, in which . matches any character, ^ the start and $ the end. list.files() reads its pattern argument as one.
relative path
A path that starts from the working directory, such as data/raw/visits.csv, rather than from the top of the disk.
Rscript
The program that runs an R script from a terminal in a new R session, which ends with the script. Words after the file name reach commandArgs().
working directory
The folder that relative paths start from. getwd() shows it; opening a project in RStudio, or starting R or Rscript in a folder, sets it.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.