ShellCheck Compatibility
Shuck can expose a ShellCheck-shaped CLI for teams that want to migrate existing editor integrations, CI jobs, or local workflows without changing every call site at once.
This mode is powered by Shuck's parser and linter, not by embedding ShellCheck itself. That means the interface is intentionally familiar, while the implementation continues to evolve with the rest of Shuck.
Activate compatibility mode
There are two supported ways to turn the compatibility surface on:
- Invoke the binary as
shellcheck. - Set
SHUCK_SHELLCHECK_COMPAT=1before runningshuck.
# Make shuck available as `shellcheck`
ln -s "$(command -v shuck)" ~/bin/shellcheck
shellcheck --version
# Or force compat mode for a single command
SHUCK_SHELLCHECK_COMPAT=1 shuck --versionCompat mode only affects that invocation. Running shuck check ... directly still uses Shuck's native CLI.
What it supports today
The compatibility surface currently covers the pieces that are most useful for migration:
- Familiar
--helpand--versionoutput - Common output formats:
tty,json,json1,checkstyle,gcc,diff, andquiet - ShellCheck-style code filtering with
--includeand--exclude - Severity filtering with
--severity - Source resolution controls like
--check-sourced,--external-sources, and--source-path - Shell overrides for
sh,bash,dash,ksh, andbusybox - Optional-check discovery with
--list-optional - Standard stdin usage with
-as the input path
# Machine-readable output for editor tooling or CI
SHUCK_SHELLCHECK_COMPAT=1 shuck -f json1 script.sh
# Only keep selected SC codes
SHUCK_SHELLCHECK_COMPAT=1 shuck --include=SC2086,SC2154 script.sh
# Follow sourced files and add extra lookup roots
SHUCK_SHELLCHECK_COMPAT=1 shuck -a -P scripts:lib main.sh.shellcheckrc support
Compat mode searches for .shellcheckrc from the current working directory upward. You can keep the default search, skip it with --norc, or point at a specific file with --rcfile.
Supported config keys today are check-sourced, color, disable, enable, extended-analysis, external-sources, format, include, severity, shell, source-path, and wiki-link-count.
# Use the nearest .shellcheckrc
shellcheck script.sh
# Ignore discovered config
shellcheck --norc script.sh
# Use an explicit config file
shellcheck --rcfile ci/shellcheckrc script.shUse Shuck with rules_lint
If your Bazel repo already uses rules_lint for shell scripts, you can swap Shuck in without rewriting the lint aspect itself. The trick is to keep exposing a shellcheck executable target and let Shuck handle the CLI compatibility layer behind that name.
One workable pattern is:
- Fetch the platform-specific Shuck release artifacts.
- Re-export each downloaded binary as an executable named
shellcheck. - Keep
lint_shellcheck_aspectpointed at your//tools:shellchecktarget.
# repositories.bzl
def shuck_deps():
SHUCK_VERSION = "<shuck-version>"
http_archive(
name = "shuck",
build_file = "//tools:shuck.BUILD.bazel",
sha256 = "<linux-x86_64-sha256>",
strip_prefix = "shuck-cli-x86_64-unknown-linux-gnu",
urls = ["https://github.com/ewhauser/shuck/releases/download/v{}/shuck-cli-x86_64-unknown-linux-gnu.tar.xz".format(SHUCK_VERSION)],
)
http_archive(
name = "shuck_linux_arm64",
build_file = "//tools:shuck.BUILD.bazel",
sha256 = "<linux-arm64-sha256>",
strip_prefix = "shuck-cli-aarch64-unknown-linux-gnu",
urls = ["https://github.com/ewhauser/shuck/releases/download/v{}/shuck-cli-aarch64-unknown-linux-gnu.tar.xz".format(SHUCK_VERSION)],
)
http_archive(
name = "shuck_osx",
build_file = "//tools:shuck.BUILD.bazel",
sha256 = "<darwin-arm64-sha256>",
strip_prefix = "shuck-cli-aarch64-apple-darwin",
urls = ["https://github.com/ewhauser/shuck/releases/download/v{}/shuck-cli-aarch64-apple-darwin.tar.xz".format(SHUCK_VERSION)],
)# tools/shuck.BUILD.bazel
package(default_visibility = ["//visibility:public"])
genrule(
name = "shellcheck_bin",
srcs = ["shuck"],
outs = ["shellcheck"],
cmd = "cp $(location shuck) $@",
executable = True,
)
filegroup(
name = "file",
srcs = [":shellcheck_bin"],
)# tools/BUILD.bazel
alias(
name = "shellcheck",
actual = select({
"@bazel_tools//src/conditions:linux_x86_64": "@shuck//:shellcheck_bin",
"@bazel_tools//src/conditions:linux_aarch64": "@shuck_linux_arm64//:shellcheck_bin",
"@bazel_tools//src/conditions:darwin_arm64": "@shuck_osx//:shellcheck_bin",
}),
visibility = ["//visibility:public"],
)For rules_lint, that alias should resolve to the executable target rather than a forwarding filegroup.
# tools/lint.bzl
load("@aspect_rules_lint//lint:lint_test.bzl", "lint_test")
load("@aspect_rules_lint//lint:shellcheck.bzl", "lint_shellcheck_aspect")
shellcheck = lint_shellcheck_aspect(
binary = "//tools:shellcheck",
config = "//:.shellcheckrc",
)
shellcheck_test = lint_test(aspect = shellcheck)That keeps your existing rules_lint entry point, target names, and .shellcheckrc file in place while swapping in Shuck as the implementation. In practice, the migration boundary stays at the tool label instead of spreading through every lint target in the repo.
Migration notes
- Exit status follows the usual ShellCheck shape:
0for no diagnostics,1when diagnostics are reported, and2for file or runtime errors. - Diagnostic codes, suppressions, and filters use
SCxxxxidentifiers, so existing# shellcheck disable=...comments continue to work. --list-optionalis available, but not every named optional check is implemented yet. Treat that catalog as a compatibility target rather than a guarantee that every check can already be enabled.- If you want Shuck-only features such as the native multi-dialect workflow or automatic fixes, use the regular
shuck checkdocs instead of the compatibility surface.
Repository conformance
This table tracks the curated large-corpus repositories that Shuck uses for ShellCheck compatibility work. Green means the checked-in corpus metadata has no known reviewed repo issues. Yellow means the repo currently has known reviewed divergences or is skipped because ShellCheck does not support it in the corpus harness.
| Repository | Status |
|---|---|
| 233boy/v2ray | 1 known issue1 known issue |
| 89luca89/distrobox | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| acmesh-official/acme.sh | 3 known issues3 known issues |
| alexanderepstein/Bash-Snippets | 2 known issues2 known issues |
| alpinelinux/aports | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| angristan/openvpn-install | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| aristocratos/bashtop | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| asdf-vm/asdf | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| awslabs/git-secrets | 1 known issue1 known issue |
| basecamp/omarchy | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| Bash-it/bash-it | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| bats-core/bats-core | 2 known issues2 known issues |
| bin456789/reinstall | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| bitnami/containers | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| bittorf/kalua | 10 known issues10 known issues |
| CISOfy/lynis | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| client9/shlib | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| community-scripts/ProxmoxVE | 25 known issues25 known issues |
| dehydrated-io/dehydrated | 1 known issue1 known issue |
| docker-library/official-images | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| docker-mailserver/docker-mailserver | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| docker/docker-bench-security | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| dockur/windows | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| dokku/dokku | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| dylanaraps/neofetch | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| dylanaraps/pure-bash-bible | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| dylanaraps/pure-sh-bible | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| fideloper/Vaprobash | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| GameServerManagers/LinuxGSM | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| gentoo/gentoo | 2 known issues2 known issues |
| google/oss-fuzz | 2 known issues2 known issues |
| HariSekhon/DevOps-Bash-tools | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| helmuthdu/aui | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| holman/dotfiles | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| hwdsl2/setup-ipsec-vpn | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| itzg/docker-minecraft-server | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| jessfraz/dotfiles | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| jorgebucaran/fisher | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| juewuy/ShellCrash | 5 known issues5 known issues |
| ko1nksm/shellspec | 2 known issues2 known issues |
| kward/shunit2 | 1 known issue1 known issue |
| leebaird/discover | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| lmc999/RegionRestrictionCheck | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| LukeSmithxyz/LARBS | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| masonr/yet-another-bench-script | 1 known issue1 known issue |
| mathiasbynens/dotfiles | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| megastep/makeself | 1 known issue1 known issue |
| moovweb/gvm | 1 known issue1 known issue |
| nextcloud/docker | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| nvie/gitflow | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| nvm-sh/nvm | 2 known issues2 known issues |
| Nyr/openvpn-install | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| oh-my-fish/oh-my-fish | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| ohmyzsh/ohmyzsh | 1 known issue1 known issue |
| openrc/openrc | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| openvpn/easy-rsa | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| p8952/bocker | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| paulirish/dotfiles | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| pi-hole/pi-hole | 4 known issues4 known issues |
| pyenv/pyenv | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| pystardust/ani-cli | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| quickemu-project/quickemu | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| rbenv/rbenv | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| RetroPie/RetroPie-Setup | 1 known issue1 known issue |
| romkatv/powerlevel10k | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| rupa/z | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| rvm/rvm | 15 known issues15 known issues |
| scop/bash-completion | 1 known issue1 known issue |
| sickcodes/Docker-OSX | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| SlackBuildsOrg/slackbuilds | 2 known issues2 known issues |
| sorin-ionescu/prezto | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| spiritLHLS/one-click-installation-script | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| sstephenson/bats | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| super-linter/super-linter | 1 known issue1 known issue |
| swoodford/aws | 2 known issues2 known issues |
| termux/termux-packages | 2 known issues2 known issues |
| thoughtbot/dotfiles | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| tj/git-extras | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| tj/n | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| tmux-plugins/tmux-resurrect | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| tmux-plugins/tpm | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| tteck/Proxmox | 15 known issues15 known issues |
| v1s1t0r1sh3r3/airgeddon | 2 known issues2 known issues |
| v2fly/fhs-install-v2ray | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| void-linux/void-packages | 1 known issue1 known issue |
| xwmx/nb | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| zdharma-continuum/zinit | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| zsh-users/zsh-autosuggestions | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| zsh-users/zsh-completions | Passes checked-in corpus conformancePasses checked-in corpus conformance |
| zsh-users/zsh-syntax-highlighting | Passes checked-in corpus conformancePasses checked-in corpus conformance |