rush convert

The convert command converts between formats without writing an expression. It reads the input, infers the output format from the file extension (or -O), and writes the result.

Usage

rush convert [options] [<file>...]

Basic conversion

rush convert -o penguins.parquet penguins.csv
rush run 'nrow(df)' penguins.parquet
#> 333
rush convert -o penguins.json --head 3 penguins.csv
cat penguins.json
#> [
#>   {
#>     "species": "Adelie",
#>     "island": "Torgersen",
#>     "bill_length_mm": 39.1,
#>     "bill_depth_mm": 18.7,
#>     "flipper_length_mm": 181,
#>     "body_mass_g": 3750,
#>     "sex": "male",
#>     "year": 2007
#>   },
#>   {
#>     "species": "Adelie",
#>     "island": "Torgersen",
#>     "bill_length_mm": 39.5,
#>     "bill_depth_mm": 17.4,
#>     "flipper_length_mm": 186,
#>     "body_mass_g": 3800,
#>     "sex": "female",
#>     "year": 2007
#>   },
#>   {
#>     "species": "Adelie",
#>     "island": "Torgersen",
#>     "bill_length_mm": 40.3,
#>     "bill_depth_mm": 18,
#>     "flipper_length_mm": 195,
#>     "body_mass_g": 3250,
#>     "sex": "female",
#>     "year": 2007
#>   }
#> ]
rush convert -O jsonl --head 2 -o penguins.jsonl penguins.csv
cat penguins.jsonl
#> {"species":"Adelie","island":"Torgersen","bill_length_mm":39.1,"bill_depth_mm":18.7,"flipper_length_mm":181,"body_mass_g":3750,"sex":"male","year":2007}
#> {"species":"Adelie","island":"Torgersen","bill_length_mm":39.5,"bill_depth_mm":17.4,"flipper_length_mm":186,"body_mass_g":3800,"sex":"female","year":2007}

Output templates

Convert multiple files using an output template with yt-dlp-style placeholders:

echo "id,val
1,a
2,b" > chunk1.csv
echo "id,val
3,c
4,d" > chunk2.csv
rush convert -o '%(file_name)s.parquet' chunk1.csv chunk2.csv
rush run 'df' chunk1.parquet
#> id,val
#> 1,a
#> 2,b

Available placeholders

Placeholder Description
%(file_name)s Input file stem
%(file_index)d 1-based file position
%(table_name)s Table name (databases)
%(table_index)d 1-based table position

The format spec after ) follows sprintf() conventions: s for string, d for integer, 03d for zero-padded. Use l for lowercase or u for uppercase:

rush convert -o '%(table_name)l.csv' sales.duckdb
rush convert -o 'table_%(table_index)03d.csv' big.duckdb

Database output

When the output is a database format (DuckDB or SQLite), multiple inputs become separate tables named after the input file stems:

echo "id,val
1,a
2,b" > a.csv
echo "id,val
3,c
4,d" > b.csv
rush convert -o combined.duckdb a.csv b.csv
rush run 'names(dfs$combined)' combined.duckdb
#> a
#> b

A single input also uses the file name as the table name:

rush convert -o penguins_db.duckdb penguins.csv
rush sql "SELECT species, COUNT(*) AS n FROM penguins_db.penguins GROUP BY species" penguins_db.duckdb
rm -f penguins_db.duckdb
#> species,n
#> Chinstrap,68
#> Gentoo,119
#> Adelie,146

Convert between database formats:

rush convert -o copy.sqlite shop.duckdb
rush run 'names(dfs$copy)' copy.sqlite

Limiting rows

Use --head to limit the number of rows written:

rush convert --head 5 -o top5.csv penguins.csv
cat top5.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,2007

Format overrides

Force input and output formats regardless of extension with -F and -O:

cp penguins.csv penguins.dat
rush convert -F csv -O json -o result.json --head 2 penguins.dat
cat result.json
rm -f penguins.dat
#> [
#>   {
#>     "species": "Adelie",
#>     "island": "Torgersen",
#>     "bill_length_mm": 39.1,
#>     "bill_depth_mm": 18.7,
#>     "flipper_length_mm": 181,
#>     "body_mass_g": 3750,
#>     "sex": "male",
#>     "year": 2007
#>   },
#>   {
#>     "species": "Adelie",
#>     "island": "Torgersen",
#>     "bill_length_mm": 39.5,
#>     "bill_depth_mm": 17.4,
#>     "flipper_length_mm": 186,
#>     "body_mass_g": 3800,
#>     "sex": "female",
#>     "year": 2007
#>   }
#> ]

Delimiter control

Read a TSV and convert to semicolon-separated CSV:

rush convert -D ";" -o cities_semi.csv cities.tsv
cat cities_semi.csv
#> city;pop;province
#> Amsterdam;921402;Noord-Holland
#> Rotterdam;655468;Zuid-Holland
#> Utrecht;361924;Utrecht
#> Den Haag;552995;Zuid-Holland

XML element names

Use --output-root and --output-record to customize the XML structure:

rush convert --output-root plants --output-record observation --head 2 -o plants.xml penguins.csv
cat plants.xml
rm -f plants.xml
#> <?xml version="1.0" encoding="UTF-8"?>
#> <plants>
#>   <observation>
#>     <species>Adelie</species>
#>     <island>Torgersen</island>
#>     <bill_length_mm>39.1</bill_length_mm>
#>     <bill_depth_mm>18.7</bill_depth_mm>
#>     <flipper_length_mm>181</flipper_length_mm>
#>     <body_mass_g>3750</body_mass_g>
#>     <sex>male</sex>
#>     <year>2007</year>
#>   </observation>
#>   <observation>
#>     <species>Adelie</species>
#>     <island>Torgersen</island>
#>     <bill_length_mm>39.5</bill_length_mm>
#>     <bill_depth_mm>17.4</bill_depth_mm>
#>     <flipper_length_mm>186</flipper_length_mm>
#>     <body_mass_g>3800</body_mass_g>
#>     <sex>female</sex>
#>     <year>2007</year>
#>   </observation>
#> </plants>

Help

rush convert -h
#> rush: Convert between file formats
#> 
#> Usage:
#>   rush convert [options] [<file>...]
#> 
#> Arguments:
#>   <file>                   Input file(s) to convert. The reader is chosen by
#>                            extension (or overridden with -F). Use '-' to read
#>                            from standard input. Output file is specified with
#>                            --output (-o); its format is inferred from extension
#>                            (or overridden with -O).
#> 
#> 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.