@eslint/shell
v0.1.0
Published
Shell language plugin for ESLint
Readme
ESLint Shell Language Plugin
A shell language plugin for ESLint, providing:
- an ESLint-style parser for shell scripts (wrapping
mvdan-sh, the parser behind
shfmt) that produces an ESTree-style syntax tree, - an ESLint language implementation so rules can traverse that tree,
- rules inspired by ShellCheck checks, and
- a recommended configuration.
Installation
npm install --save-dev eslint @eslint/shellRequires Node.js ^20.19.0 || ^22.13.0 || >=24. Tested with ESLint v10.
Usage
Add the plugin to your eslint.config.js:
import shell from "@eslint/shell";
export default [
// use the recommended rules for *.sh and *.bash files
shell.configs.recommended,
];Or configure it manually:
import shell from "@eslint/shell";
export default [
{
files: ["**/*.sh"],
plugins: { shell },
language: "shell/bash",
rules: {
"shell/no-backticks": "error",
"shell/no-unquoted-expansions": "error",
},
},
];Languages
The plugin provides one language per shell dialect:
| Language | Description |
| ------------- | ------------------------------------- |
| shell/bash | Bash. Used by the recommended config. |
| shell/posix | POSIX sh, without Bash extensions. |
| shell/mksh | MirBSD Korn shell. |
export default [
{
files: ["**/*.sh"],
plugins: { shell },
language: "shell/posix",
rules: { "shell/no-backticks": "error" },
},
];Rules
Each rule mirrors a well-known ShellCheck check.
| Rule | ShellCheck | Description | Fixable | Recommended |
| ---------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------- | ------- | ----------- |
| no-backticks | SC2006 | Use $(...) instead of legacy backticks | ✅ | error |
| no-expansions-in-single-quotes | SC2016 | Expressions don't expand in single quotes | | warn |
| no-ls-iteration | SC2045 | Don't iterate over ls output; use globs | | error |
| no-unquoted-expansions | SC2086/46 | Quote expansions subject to word splitting and globbing | ✅ | error |
| no-unused-vars | SC2034 | Disallow variables that are assigned but never used | | error |
| no-useless-cat | SC2002 | Don't pipe from a single-file cat | | error |
| no-useless-echo | SC2116 | Disallow $(echo ...) | | error |
| no-variables-in-printf-format | SC2059 | Don't put variables in the printf format string | | error |
| require-cd-guard | SC2164 | Handle cd failure with \|\| exit (has suggestions) | | error |
| require-read-r | SC2162 | Use read -r so backslashes aren't mangled | ✅ | error |
Rule options
shell/no-unused-vars accepts an object option:
"shell/no-unused-vars": ["error", { allowed: ["MY_GLOBAL"] }]Configuration comments
Standard ESLint configuration comments work inside shell scripts:
# eslint-disable-next-line shell/no-backticks
echo `pwd`
echo `pwd` # eslint-disable-line shell/no-backticks -- legacy
# eslint shell/no-useless-echo: "warn"Syntax tree
The tree format is documented in docs/syntax-tree.md.
Nodes carry start/end character offsets instead of range/loc
properties; use sourceCode.getRange(node) and sourceCode.getLoc(node).
The parser is also exported directly:
import { parseShell } from "@eslint/shell";
const { ast, comments } = parseShell('echo "hello"\n');Development
npm install
npm test # unit + integration tests (Vitest)
npm run lint # ESLint on the plugin's own sources
npm run fmt # Prettier
npm run build # compile TypeScript to dist/Pre-commit hooks (via yorkie and lint-staged) run Prettier and ESLint on staged files. Releases are managed with release-please through GitHub Actions.
License
Apache-2.0
Sponsors
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. Become a Sponsor to get your logo on our READMEs and website.
