Getting Started
Shuck is a Rust toolkit for working with shell scripts: linting, formatting, editor feedback, and managed shell execution from one CLI.
- โก Lint 20-100x faster than ShellCheck in benchmarked runs, with per-file caching for incremental checks.
- ๐ Work across bash, sh/POSIX, dash, ksh, mksh, and zsh from the same binary.
- ๐งฉ Check shell scripts and embedded GitHub Actions
run:blocks with parser-backed diagnostics. - ๐ช Format shell files from the command line, CI, or an editor through LSP formatting.
- ๐ฅ๏ธ Use the LSP server for live diagnostics, quick fixes, hover help, navigation, and format-on-save.
- ๐งช Run scripts with managed shell interpreters when you need reproducible local or CI behavior.
- ๐ค Keep ShellCheck-compatible suppressions and CLI migration paths for existing workflows.
- ๐ฆ Install one dependency-free executable for local development, editors, and CI.
Shuck is built around one shared shell parser, so the CLI, formatter, linter, and language server agree on how each script is understood.
Installation
PyPI
pip install shuck-cliThe PyPI package name is shuck-cli, but it still installs the shuck
command.
From source
cargo install shuck-cliPre-built binaries
Pre-built binaries are available for macOS (aarch64) and Linux (x86_64) from the releases page.
Linting
# Check files and directories
shuck check script.sh src/
# Check the current directory
shuck check .
# Check embedded GitHub Actions `run:` blocks
shuck check .github/workflows/ci.yml
# Read from stdin
echo 'echo $foo' | shuck check -
# Apply safe fixes automatically
shuck check --fix .See the dedicated Linting guide for rule selection, fixes, output formats, watch mode, per-file shell overrides, and CI behavior.
Formatting
Shuck includes a formatter for standalone shell files:
# Format the current project in place
shuck format .
# Check formatting in CI
shuck format --check .
# Print a diff without changing files
shuck format --diff .See the dedicated Formatting guide for formatter config, stdin usage, dialect overrides, and LSP formatting support.
Pre-commit
Use the published wheel-backed hook when you want pre-commit support without a local Rust toolchain:
repos:
- repo: https://github.com/ewhauser/shuck
rev: v0.0.35
hooks:
- id: shuckReplace v0.0.35 with the release you want to pin.
Use the source fallback instead when you prefer to run from the Rust checkout or need an unsupported platform:
repos:
- repo: https://github.com/ewhauser/shuck
rev: v0.0.35
hooks:
- id: shuck-srcThe shuck-src hook requires a working Rust toolchain because it runs
cargo run -p shuck-cli -- check ... from the cloned hook repository.
LSP server
Shuck also ships with a first-party LSP server over stdio:
shuck serverSee the dedicated LSP Server guide for setup examples in Neovim, Vim, Emacs, and Zed.
Managed runtime
Shuck can also run scripts with managed shell interpreters instead of whatever version happens to be installed on your machine.
# Run with the resolved interpreter for this script
shuck run deploy.sh
# Pin a specific shell version
shuck run --shell bash --shell-version 5.2 deploy.shSee the dedicated Managed Runtime guide for version resolution, inline metadata, [run] config, shuck install, and shuck shell.
Suppression
Use inline comments to suppress warnings for a line, a command, or a whole file. Shuck supports both native # shuck: directives and ShellCheck-compatible # shellcheck directives, including mapped SC codes.
See the dedicated Suppression guide for examples of both syntaxes.
Zsh support
Shuck treats zsh as a first-class dialect and can resolve common oh-my-zsh plugin setups in real startup files such as .zshrc.
See the dedicated Zsh Support guide for dotfile detection, plugin-resolution examples, and the zsh-specific config and CLI flags.
ShellCheck compatibility mode
If you already have tools that invoke shellcheck, Shuck can expose a ShellCheck-shaped CLI without changing your primary workflow all at once.
See the dedicated ShellCheck compatibility guide for activation, supported flags, .shellcheckrc handling, and current caveats.
Use Shuck with rules_lint
If you use rules_lint for shell scripts in Bazel, you can keep the existing ShellCheck-shaped lint hook and swap in Shuck underneath it.
See the dedicated rules_lint replacement example for the Bazel targets and compatibility setup.
Embedded scripts
Shuck also lints shell embedded in supported GitHub Actions workflows and composite actions. See the dedicated Embedded Scripts guide for supported files, shell resolution, diagnostic remapping, and suppression behavior inside run: blocks.