rush run '6 * 7'
#> 42rush run
The run command evaluates an R expression and prints (or saves) the result. It is the core command of rush.
Usage
rush run [options] [<expression>] [--] [<file>...]Simple expressions
At its core, rush run evaluates any R expression and prints the result:
Multiple semicolon-separated expressions work; the value of the last one is printed:
rush run 'x <- 1:10; mean(x)'
#> 5.5Strings, vectors, and lists all print naturally:
rush run 'paste("Hello", "from", "R", sep = ", ")'
#> Hello, from, Rrush run 'rev(LETTERS[1:8])'
#> H
#> G
#> F
#> E
#> D
#> C
#> B
#> AReading input files
Pass a file path after the expression, and it is read into a data frame called df:
rush run 'nrow(df)' penguins.csv
#> 333With just a file and no expression, the data is printed. A quick way to peek:
rush run 'head(df, 5)' penguins.csv
#> species,island,bill_length_mm,bill_depth_mm,flipper_length_mm,body_mass_g,sex,year
#> Adelie,Torgersen,39.1,18.7,181,3750,male,2007
#> Adelie,Torgersen,39.5,17.4,186,3800,female,2007
#> Adelie,Torgersen,40.3,18,195,3250,female,2007
#> Adelie,Torgersen,36.7,19.3,193,3450,female,2007
#> Adelie,Torgersen,39.3,20.6,190,3650,male,2007The df and dfs variables
Two variables are always available in your expression:
df: the first input (a data frame for flat files, or a named list of tables for database files).dfs: a named list of all inputs, keyed by file stem. Database entries are nested one level deeper:dfs$dbname$tablename.
rush run 'names(dfs)' penguins.csv cities.tsv
#> penguins
#> citiesrush run 'nrow(dfs[["penguins"]])' penguins.csv cities.tsv
#> 333Reading from standard input
Use - to read from stdin. This makes rush composable in shell pipelines:
echo "name,score
Alice,92
Bob,85
Carol,97" | rush run 'df |> dplyr::arrange(dplyr::desc(score))' -
#> name,score
#> Carol,97
#> Alice,92
#> Bob,85You can pipe the output of one rush into another:
rush run 'head(df, 5)' penguins.csv | rush run 'dplyr::select(df, species, bill_length_mm, body_mass_g)' -
#> species,bill_length_mm,body_mass_g
#> Adelie,39.1,3750
#> Adelie,39.5,3800
#> Adelie,40.3,3250
#> Adelie,36.7,3450
#> Adelie,39.3,3650Use -F to read non-CSV formats from stdin, for example JSON:
rush run -O json 'head(df, 3)' penguins.csv | rush run -F json 'dplyr::select(df, species, body_mass_g)' -
#> species,body_mass_g
#> Adelie,3750
#> Adelie,3800
#> Adelie,3250Reading DuckDB databases
Point rush at a .duckdb file and all tables are loaded into dfs:
rush run 'names(dfs$shop)' shop.duckdb
#> customers
#> ordersOptions
--delimiter (-d)
Override the delimiter for both reading and writing:
rush run -d "\t" 'head(df, 3)' cities.tsv
#> city\pop\province
#> Amsterdam\921402\Noord-Holland
#> Rotterdam\655468\Zuid-Holland
#> Utrecht\361924\UtrechtWrite tab-separated output:
rush run -d "\t" 'head(df, 3)' penguins.csv | cat
#> species_island_bill_length_mm_bill_depth_mm_flipper_length_mm_body_mass_g_sex_year
#> Adelie,Torgersen,39.1,18.7,181,3750,male,2007
#> Adelie,Torgersen,39.5,17.4,186,3800,female,2007
#> Adelie,Torgersen,40.3,18,195,3250,female,2007--no-header (-H)
Suppress headers on both input and output. Input columns are auto-named x1, x2, …:
rush run -H 'sum(df$x1)' numbers.txt
#> 150seq 5 | rush run -H 'cumsum(df$x1)' -
#> 1
#> 3
#> 6
#> 10
#> 15--no-input-header
Read without a header row, but still include a header in the output:
seq 5 | rush run --no-input-header 'cumsum(df$x1)' -
#> 1
#> 3
#> 6
#> 10
#> 15--no-output-header
Read normally but omit the header row from the output:
rush run --no-output-header 'head(df, 3)' penguins.csv | cat
#> Adelie,Torgersen,39.1,18.7,181,3750,male,2007
#> Adelie,Torgersen,39.5,17.4,186,3800,female,2007
#> Adelie,Torgersen,40.3,18,195,3250,female,2007--names
Provide explicit column names (comma-separated). Implies --no-input-header:
echo -e "1,Alice\n2,Bob" | rush run --names "id,name" 'df'--no-clean-names (-C)
By default, rush normalizes column names (lowercase, underscores). Disable with -C to preserve the originals:
echo "First Name,Last Name,Score (%)
Alice,Smith,92" | rush run 'names(df)' -
#> first_name
#> last_name
#> score_percentecho "First Name,Last Name,Score (%)
Alice,Smith,92" | rush run -C 'names(df)' -
#> First Name
#> Last Name
#> Score (%)--tidyverse (-t)
Load the entire Tidyverse (plus glue) so you can use dplyr, tidyr, stringr, etc. without qualifying names:
rush run -t 'df |> group_by(species) |> summarise(mean_mass = mean(body_mass_g)) |> arrange(desc(mean_mass))' penguins.csv
#> species,mean_mass
#> Gentoo,5092.436974789916
#> Chinstrap,3733.0882352941176
#> Adelie,3706.1643835616437--library (-l)
Load specific packages. Comma-separate multiple packages:
rush run -l stringr 'stringr::str_to_title("hello world")'
#> Hello Worldrush run -l dplyr,tidyr 'df |>
tidyr::pivot_longer(cols = c(bill_length_mm, bill_depth_mm), names_to = "metric") |>
dplyr::slice_head(n = 4)' penguins.csv
#> species,island,flipper_length_mm,body_mass_g,sex,year,metric,value
#> Adelie,Torgersen,181,3750,male,2007,bill_length_mm,39.1
#> Adelie,Torgersen,181,3750,male,2007,bill_depth_mm,18.7
#> Adelie,Torgersen,186,3800,female,2007,bill_length_mm,39.5
#> Adelie,Torgersen,186,3800,female,2007,bill_depth_mm,17.4--seed
Set the random seed for reproducible results:
rush run --seed 42 'sample(1:100, 5)'
#> 49
#> 65
#> 25
#> 74
#> 18Run it again; same seed, same result:
rush run --seed 42 'sample(1:100, 5)'
#> 49
#> 65
#> 25
#> 74
#> 18--output (-o)
Write the result to a file instead of stdout. The output format is inferred from the extension:
rush run -o summary.csv 'data.frame(stat = c("min", "mean", "max"),
mass = c(min(df$body_mass_g), mean(df$body_mass_g), max(df$body_mass_g)))' penguins.csv
cat summary.csv
#> stat,mass
#> min,2700
#> mean,4207.057057057057
#> max,6300Write to Parquet:
rush run -o subset.parquet 'dplyr::filter(df, body_mass_g > 5000)' penguins.csv
rush run 'df' subset.parquet
#> species,island,bill_length_mm,bill_depth_mm,flipper_length_mm,body_mass_g,sex,year
#> Gentoo,Biscoe,50,16.3,230,5700,male,2007
#> Gentoo,Biscoe,50,15.2,218,5700,male,2007
#> Gentoo,Biscoe,47.6,14.5,215,5400,male,2007
#> Gentoo,Biscoe,46.7,15.3,219,5200,male,2007
#> Gentoo,Biscoe,46.8,15.4,215,5150,male,2007
#> Gentoo,Biscoe,49,16.1,216,5550,male,2007
#> Gentoo,Biscoe,48.4,14.6,213,5850,male,2007
#> Gentoo,Biscoe,49.3,15.7,217,5850,male,2007
#> Gentoo,Biscoe,49.2,15.2,221,6300,male,2007
#> Gentoo,Biscoe,48.7,15.1,222,5350,male,2007
#> Gentoo,Biscoe,50.2,14.3,218,5700,male,2007
#> Gentoo,Biscoe,46.3,15.8,215,5050,male,2007
#> Gentoo,Biscoe,46.1,15.1,215,5100,male,2007
#> Gentoo,Biscoe,47.8,15,215,5650,male,2007
#> Gentoo,Biscoe,50,15.3,220,5550,male,2007
#> Gentoo,Biscoe,47.3,15.3,222,5250,male,2007
#> Gentoo,Biscoe,45.1,14.5,207,5050,female,2007
#> Gentoo,Biscoe,59.6,17,230,6050,male,2007
#> Gentoo,Biscoe,49.1,14.8,220,5150,female,2008
#> Gentoo,Biscoe,48.4,16.3,220,5400,male,2008
#> Gentoo,Biscoe,44.4,17.3,219,5250,male,2008
#> Gentoo,Biscoe,48.7,15.7,208,5350,male,2008
#> Gentoo,Biscoe,49.6,16,225,5700,male,2008
#> Gentoo,Biscoe,50.5,15.9,222,5550,male,2008
#> Gentoo,Biscoe,50.5,15.9,225,5400,male,2008
#> Gentoo,Biscoe,44.9,13.3,213,5100,female,2008
#> Gentoo,Biscoe,45.2,15.8,215,5300,male,2008
#> Gentoo,Biscoe,48.5,14.1,220,5300,male,2008
#> Gentoo,Biscoe,45,15.4,220,5050,male,2008
#> Gentoo,Biscoe,50.4,15.3,224,5550,male,2008
#> Gentoo,Biscoe,46.2,14.9,221,5300,male,2008
#> Gentoo,Biscoe,54.3,15.7,231,5650,male,2008
#> Gentoo,Biscoe,49.8,16.8,230,5700,male,2008
#> Gentoo,Biscoe,49.5,16.2,229,5800,male,2008
#> Gentoo,Biscoe,50.7,15,223,5550,male,2008
#> Gentoo,Biscoe,48.2,15.6,221,5100,male,2008
#> Gentoo,Biscoe,46.5,14.8,217,5200,female,2008
#> Gentoo,Biscoe,48.6,16,230,5800,male,2008
#> Gentoo,Biscoe,51.1,16.3,220,6000,male,2008
#> Gentoo,Biscoe,45.2,16.4,223,5950,male,2008
#> Gentoo,Biscoe,52.5,15.6,221,5450,male,2009
#> Gentoo,Biscoe,50,15.9,224,5350,male,2009
#> Gentoo,Biscoe,50.8,17.3,228,5600,male,2009
#> Gentoo,Biscoe,51.3,14.2,218,5300,male,2009
#> Gentoo,Biscoe,52.1,17,230,5550,male,2009
#> Gentoo,Biscoe,52.2,17.1,228,5400,male,2009
#> Gentoo,Biscoe,49.5,16.1,224,5650,male,2009
#> Gentoo,Biscoe,50.8,15.7,226,5200,male,2009
#> Gentoo,Biscoe,51.1,16.5,225,5250,male,2009
#> Gentoo,Biscoe,55.9,17,228,5600,male,2009
#> Gentoo,Biscoe,49.1,15,228,5500,male,2009
#> Gentoo,Biscoe,46.8,16.1,215,5500,male,2009
#> Gentoo,Biscoe,53.4,15.8,219,5500,male,2009
#> Gentoo,Biscoe,48.1,15.1,209,5500,male,2009
#> Gentoo,Biscoe,49.8,15.9,229,5950,male,2009
#> Gentoo,Biscoe,51.5,16.3,230,5500,male,2009
#> Gentoo,Biscoe,55.1,16,230,5850,male,2009
#> Gentoo,Biscoe,48.8,16.2,222,6000,male,2009
#> Gentoo,Biscoe,50.4,15.7,222,5750,male,2009
#> Gentoo,Biscoe,45.2,14.8,212,5200,female,2009
#> Gentoo,Biscoe,49.9,16.1,213,5400,male,2009--output-root, --output-record
Customize the XML element names when writing XML. Defaults are root (root) and record (each record). Also used by TOML for the record name:
rush run -n -O xml --output-root plants --output-record observation 'head(df)' data.csv
#> #!/usr/bin/env -S ir run
#> #| packages:
#> #| - rush
#>
#> rush::init(
#> output_format = "xml",
#> dpi = 300L,
#> output_root = "plants",
#> output_record = "observation"
#> )
#>
#> dfs <- list()
#> dfs[["data"]] <- rush::read("data.csv")
#> df <- dfs[[1]]
#> result <- head(df)
#>
#> rush::write(result)--dry-run (-n)
Print the generated script instead of running it. Great for learning what rush does under the hood, or for saving scripts:
rush run -n 'df |> dplyr::filter(body_mass_g > 5000)' penguins.csv
#> #!/usr/bin/env -S ir run
#> #| packages:
#> #| - rush
#>
#> rush::init(
#> dpi = 300L
#> )
#>
#> dfs <- list()
#> dfs[["penguins"]] <- rush::read("penguins.csv")
#> df <- dfs[[1]]
#> result <- dplyr::filter(df, body_mass_g > 5000)
#>
#> rush::write(result)--no-ir (-I)
Run with plain Rscript instead of ir. No package resolution happens – everything must already be installed:
rush run -I '2 + 2'
#> 4--verbose (-v)
Show parsed arguments before running. Useful for debugging complex invocations:
rush run -v --seed 7 'sum(1:10)' 2>&1
#> ── Arguments ───────────────────────────────────────────────────────────────────
#> • command <chr> "run"
#> • delimiter <chr> ","
#> • dpi <int> 300L
#> • dry_run <lgl> FALSE
#> • expression <language> list(sum(1:10))
#> • file <list> list()
#> • head <NULL>
#> • height <NULL>
#> • help <lgl> FALSE
#> • input_delimiter <NULL>
#> • input_format <chr> "auto"
#> • input_sheet <NULL>
#> • library <NULL>
#> • names <NULL>
#> • no_clean_names <lgl> FALSE
#> • no_header <lgl> FALSE
#> • no_input_header <lgl> FALSE
#> • no_ir <lgl> FALSE
#> • no_output_header <lgl> FALSE
#> • no_rush <lgl> FALSE
#> • output <NULL>
#> • output_delimiter <NULL>
#> • output_format <chr> "auto"
#> • output_indent <int> 2L
#> • output_record <chr> "record"
#> • output_root <chr> "root"
#> • output_sheet <NULL>
#> • run <lgl> TRUE
#> • seed <int> 7L
#> • tidyverse <lgl> FALSE
#> • units <chr> "in"
#> • verbose <lgl> TRUE
#> • version <lgl> FALSE
#> • width <NULL>
#> • resolved_no_input_header <lgl> FALSE
#> • resolved_no_output_header <lgl> FALSE
#> • resolved_col_names <lgl> TRUE
#> • resolved_input_delimiter <chr> ","
#> • resolved_output_delimiter <chr> ","
#> • resolved_output_format <chr> "delim"
#> ────────────────────────────────────────────────────────────────────────────────
#> 55Help
rush run -h
#> rush: Run an R expression
#>
#> Usage:
#> rush run [options] [<expression>] [--] [<file>...]
#>
#> Arguments:
#> <expression> R expression to evaluate. The value of the last
#> expression is printed or written out.
#> <file> Data file(s) to read. Two variables are always set:
#> 'df' (the first input) and 'dfs' (a named list of
#> all inputs, keyed by file stem). Database files
#> (.duckdb, .sqlite) are nested one level deeper:
#> dfs$dbname$tablename. The reader is chosen by
#> extension. Use '-' to read from standard input
#> (becomes dfs$stdin).
#>
#> Note: -d/--delimiter sets both input and output delimiter. Use -F, -D, or -O
#> to override format and delimiter for each side independently.
#>
#> Reading options:
#> -d, --delimiter <str> Delimiter (input and output) [default: ,].
#> --input-delimiter <str> Input delimiter (overrides -d).
#> -F, --input-format <format> Input format [default: auto].
#> --input-sheet <name|int> Excel sheet to read.
#> --names <a,b,c> Column names (implies no input header).
#> -C, --no-clean-names No clean names.
#> -H, --no-header No header (input and output).
#> --no-input-header No input header.
#> --no-output-header No output header.
#>
#> Setup options:
#> -l, --library <name> Libraries to load.
#> -t, --tidyverse Enter the Tidyverse.
#>
#> Saving options:
#> --dpi <int> Plot resolution [default: 300].
#> --head <int> Limit output rows.
#> --height <num> Plot height.
#> -o, --output <str> Output file.
#> -D, --output-delimiter <str> Output delimiter (overrides -d).
#> -O, --output-format <format> Output format [default: auto].
#> --output-indent <int> Indentation level (JSON, YAML) [default: 2].
#> --output-record <str> Record element name (XML, TOML) [default: record].
#> --output-root <str> Root element name (XML) [default: root].
#> --output-sheet <str> Excel sheet name to write.
#> --units <str> Plot size units [default: in].
#> -w, --width <num> Plot width.
#>
#> General options:
#> -n, --dry-run Only print generated script.
#> -h, --help Show this help.
#> -I, --no-ir Run with Rscript, not ir.
#> -R, --no-rush Inline all code (no rush dep).
#> --seed <int> Seed random number generator.
#> -v, --verbose Be verbose.
#> --version Show version.