Skip to content

Files

Latest commit

b80b3df · Jan 1, 2025

History

History

docs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Oct 27, 2020
Jan 1, 2025
Oct 27, 2020
Nov 4, 2020
<style> ul li:not(:last-child) { margin-bottom: 0.4em; } </style>

Overview

With rust-script Rust files and expressions can be executed just like a shell or Python script. Features include:

  • Caching compiled artifacts for speed.
  • Reading Cargo manifests embedded in Rust scripts.
  • Supporting executable Rust scripts via Unix shebangs and Windows file associations.
  • Using expressions as stream filters (i.e. for use in command pipelines).
  • Running unit tests and benchmarks from scripts.

You can get an overview of the available options using the --help flag.

News

See the changelog for information about releases and changes.

Installation

Install or update rust-script using Cargo:

cargo install rust-script

Rust 1.74 or later is required.

Distro Packages

Arch Linux

rust-script can be installed from the extra repository:

pacman -S rust-script

Homebrew

rust-script can be installed from the Homebrew:

brew install rust-script

Scripts

The primary use for rust-script is for running Rust source files as scripts. For example:

$ echo 'println!("Hello, World!");' > hello.rs
$ rust-script hello.rs
Hello, World!

Under the hood, a Cargo project will be generated and built (with the Cargo output hidden unless compilation fails or the -c/--cargo-output option is used). The first invocation of the script will be slower as the script is compiled - subsequent invocations of unmodified scripts will be fast as the built executable is cached.

As seen from the above example, using a fn main() {} function is not required. If not present, the script file will be wrapped in a fn main() { ... } block.

rust-script will look for embedded dependency and manifest information in the script as shown by the below two equivalent now.rs variants:

#!/usr/bin/env rust-script
//! This is a regular crate doc comment, but it also contains a partial
//! Cargo manifest.  Note the use of a *fenced* code block, and the
//! `cargo` "language".
//!
//! ```cargo
//! [dependencies]
//! time = "0.1.25"
//! ```
fn main() {
    println!("{}", time::now().rfc822z());
}
// cargo-deps: time="0.1.25"
// You can also leave off the version number, in which case, it's assumed
// to be "*".  Also, the `cargo-deps` comment *must* be a single-line
// comment, and it *must* be the first thing in the file, after the
// shebang.
// Multiple dependencies should be separated by commas:
// cargo-deps: time="0.1.25", libc="0.2.5"
fn main() {
    println!("{}", time::now().rfc822z());
}

The output from running one of the above scripts may look something like:

$ rust-script now
Wed, 28 Oct 2020 00:38:45 +0100

Useful command-line arguments:

  • --bench: Compile and run benchmarks. Requires a nightly toolchain.
  • --debug: Build a debug executable, not an optimised one.
  • --force: Force the script to be rebuilt. Useful if you want to force a recompile with a different toolchain.
  • --package: Generate the Cargo package and print the path to it - but don't compile or run it. Effectively "unpacks" the script into a Cargo package.
  • --test: Compile and run tests.
  • --wrapper: Add a wrapper around the executable. Can be used to run debugging with e.g. rust-script --debug --wrapper rust-lldb my-script.rs or benchmarking with rust-script --wrapper "hyperfine --runs 100" my-script.rs

Executable Scripts

On Unix systems, you can use #!/usr/bin/env rust-script as a shebang line in a Rust script. This will allow you to execute a script files (which don't need to have the .rs file extension) directly.

If you are using Windows, you can associate the .ers extension (executable Rust - a renamed .rs file) with rust-script. This allows you to execute Rust scripts simply by naming them like any other executable or script.

This can be done using the rust-script --install-file-association command. Uninstall the file association with rust-script --uninstall-file-association.

If you want to make a script usable across platforms, use both a shebang line and give the file a .ers file extension.

Expressions

Using the -e/--expr option a Rust expression can be evaluated directly, with dependencies (if any) added using -d/--dep:

$ rust-script -e '1+2'
3
$ rust-script --dep time --expr "time::OffsetDateTime::now_utc().format(time::Format::Rfc3339).to_string()"`
"2020-10-28T11:42:10+00:00"
$ # Use a specific version of the time crate (instead of default latest):
$ rust-script --dep time=0.1.38 -e "time::now().rfc822z().to_string()"
"2020-10-28T11:42:10+00:00"

The code given is embedded into a block expression, evaluated, and printed out using the Debug formatter (i.e. {:?}).

Filters

You can use rust-script to write a quick filter, by specifying a closure to be called for each line read from stdin, like so:

$ cat now.ers | rust-script --loop \
    "let mut n=0; move |l| {n+=1; println!(\"{:>6}: {}\",n,l.trim_end())}"
     1: // cargo-deps: time="0.1.25"
     3: fn main() {
     4:     println!("{}", time::now().rfc822z());
     5: }

You can achieve a similar effect to the above by using the --count flag, which causes the line number to be passed as a second argument to your closure:

$ cat now.ers | rust-script --count --loop \
    "|l,n| println!(\"{:>6}: {}\", n, l.trim_end())"
     1: // cargo-deps: time="0.1.25"
     2: fn main() {
     3:     println!("{}", time::now().rfc822z());
     4: }

Environment Variables

The following environment variables are provided to scripts by rust-script:

  • RUST_SCRIPT_BASE_PATH: the base path used by rust-script to resolve relative dependency paths. Note that this is not necessarily the same as either the working directory, or the directory in which the script is being compiled.

  • RUST_SCRIPT_PKG_NAME: the generated package name of the script.

  • RUST_SCRIPT_SAFE_NAME: the file name of the script (sans file extension) being run. For scripts, this is derived from the script's filename. May also be "expr" or "loop" for those invocations.

  • RUST_SCRIPT_PATH: absolute path to the script being run, assuming one exists. Set to the empty string for expressions.

Troubleshooting

Please report all issues on the GitHub issue tracker.

If relevant, run with the RUST_LOG=rust_script=trace environment variable set to see verbose log output and attach that output to an issue.