Skip to content

PlayForm/Run

Run 🍺 (prun)

Run is a blazingly fast, concurrent command-line utility for executing commands across multiple directories that match a specific pattern.

It's designed as a modern, high-performance replacement for complex find ... -execdir pipelines, leveraging Rust's full potential for safe, parallel, and asynchronous operations.

Key Features 🔐

  • Blazing Fast: Drastically out-performs traditional shell equivalents by using an optimized parallel directory walker and asynchronous command execution.
  • Concurrent by Default: Runs tasks in parallel using a hybrid rayon and tokio approach to maximize CPU and I/O efficiency.
  • Intuitive Syntax: Replaces complex find and xargs syntax with simple, readable flags.
  • Smart Exclusion: Comes with sensible defaults to automatically ignore common directories like node_modules, .git, and target.
  • Cross-Platform: Built with Rust, Run works consistently across Windows, macOS, and Linux.

Performance Benchmarks 🚤

Run is significantly faster than its find -execdir equivalent. The benchmarks below were performed on a Windows machine with an NVMe SSD and 6 core CPU (AMD Ryzen 5 5500) with 32 GB of DDR4 RAM, scanning a large developer directory with hundreds of Git repositories.

Command: Time:
Run -P .git -C 'ls'
real    0m3.484s
user    0m0.045s
sys     0m0.031s
Run -P .git -C 'git status'
real    0m7.412s
user    0m0.045s
sys     0m0.031s
find -iname .git -execdir ls \;
real    0m10.562s
user    0m3.092s
sys     0m6.789s
find -iname .git -execdir git status \;
real    0m30.352s
user    0m3.218s
sys     0m7.286s

Why is it so much faster?

  • find executes commands sequentially, one after another.
  • Run walks the directory tree once and then executes all commands in parallel, taking full advantage of modern multi-core processors and fast I/O.

Installation 🚀

You can install Run directly from Crates.io using Cargo:

cargo install prun

The installed binary is Run. You may want to create a symlink or alias like prun for convenience.


Usage ⚙️

The core idea is to define a Pattern (like a file or directory name) that identifies the locations where you want to execute one or more Commands.

A utility to run commands in directories matching a pattern.

Usage: Run [OPTIONS] --Pattern <PATTERN> --Command <COMMAND>...

Options:
  -F, --File               Target files directly instead of directories containing a pattern
  -P, --Parallel           Execute commands in parallel across all found directories
  -R, --Root <DIRECTORY>   The root directory to start the search from [default: .]
  -E, --Exclude <PATTERNS> A space-separated list of glob patterns to exclude from the search [default: **/{node_modules,.git,target,dist,vendor}/**/*]
  -C, --Command <COMMAND>  The command to execute. Can be specified multiple times
  -h, --help               Print help
  -V, --version            Print version

Basic Examples

1. Fetch all Git repositories in the current directory.

This will find every directory containing a .git subfolder and run git fetch inside it.

Run --Pattern .git --Command "git fetch --all"

This is the high-performance equivalent of: find . -type d -name .git -execdir git fetch --all \;

2. Run multiple commands.

Clean the target directory for all Rust projects.

Run --Pattern Cargo.toml --Command "cargo clean" --Command "echo Cleaned"

3. Run npm install in all projects with a package.json.

The default --Exclude rules will automatically prevent it from running inside node_modules.

Run --Pattern package.json --Command "npm install"

Advanced Options

  • -R, --Root <DIRECTORY>: Start searching from a different directory.

    Run --Root ~/projects --Pattern .git --Command "git status -s"
  • -P, --Parallel: You can run things sequentially by omitting it if sequential execution is preferred.

  • -E, --Exclude <PATTERNS>: Override the default exclusion patterns. Note that patterns are space-separated.

    # Also exclude 'build' and 'cache' directories
    Run --Pattern .git -E "**/{node_modules,target,dist,build,cache}/**/*" -C "git status"
  • -F, --File: Target files directly based on the pattern. This is less common. For example, to run a linter on all TypeScript config files:

    Run -F --Pattern "tsconfig.json" --Command "npx eslint tsconfig.json"

Dependencies 🖇️

Run stands on the shoulders of giants. It is built with these excellent crates from the Rust ecosystem:

  • clap: For robust and ergonomic command-line argument parsing.
  • walkdir: For efficient, cross-platform directory traversal.
  • globset: For high-performance file path matching against glob patterns.
  • tokio: The de-facto asynchronous runtime for writing fast and reliable network and I/O-bound applications.
  • rayon: A data-parallelism library that makes it easy to convert sequential computations into parallel ones.
  • futures: Provides core abstractions for asynchronous programming.
  • crossbeam-queue: For high-performance, lock-free queues used in our concurrent pipeline.
  • once_cell: For safe, efficient, and thread-safe one-time initialization of global state.

License ⚖️

This project is released into the public domain under the Creative Commons CC0 Universal license. You are free to use, modify, distribute, and build upon this work for any purpose, without any restrictions. For the full legal text, see the LICENSE file.


Changelog 📜

Stay updated with our progress! See CHANGELOG.md for a history of changes specific to Run.

About

Run 🍺

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages