Shell scripts
Index¶
- shell_scripts::has_shell_shebang
- shell_scripts::is_shell_file
- shell_scripts::assert_paths_exist
- shell_scripts::find
- shell_scripts::filter
- shell_scripts::find_root_only
- shell_scripts::requires_help_flag
shell_scripts::has_shell_shebang¶
Return true if the given file's first line contains a bash, sh, or bats shebang. bats is included because shfmt and shellcheck both auto-detect it from the shebang and apply their bats-aware dialect.
Arguments¶
- $1 (file): path
Exit codes¶
- 0: if true
- 1: if false
shell_scripts::is_shell_file¶
Return true if the given path is a shell file: either it carries a shell
extension (.sh/.bash/.bats) or its first line is a shell shebang. Mirrors how
shfmt --find classifies files when scanning a directory, so an explicitly
passed file is judged by the same rule a discovered one is. .bats is matched by
extension because those files open with @test, not a shebang.
Arguments¶
- $1 (file): path
Exit codes¶
- 0: if true
- 1: if false
shell_scripts::assert_paths_exist¶
Die if any of the given paths does not exist on disk.
Arguments¶
- ... (paths): to validate
shell_scripts::find¶
Emit shell-script paths under the repo root when called with no args; excludes
/other/ (third-party copies), /.shdoc/ (vendored shdoc submodule), and
/.direnv/ (Nix/direnv-managed cache). With args: each arg is either a
directory (recursed via shfmt --find) or a file (emitted as-is). Caller
must validate that each arg exists before calling.
Output: stdout — shell script file paths, one per line
Arguments¶
- ... (files): or directories to search (optional; defaults to all scripts under the repo root)
Exit codes¶
- 0: at least one shell file was emitted
- 1: the no-args scan matched nothing
shell_scripts::filter¶
Filter candidate paths down to processable shell scripts: - Files that are not shell files are warned and skipped. A shell file is one carrying a .sh/.bash/.bats extension or a shell shebang (shell_scripts::is_shell_file), the same predicate the shfmt step in check-scripts uses. Gating on the shebang alone would leave 31 of 83 test files silently unlinted. - Files under /other/ require interactive confirmation (prompt::ny). Output goes into a caller-provided array via nameref so prompts can run in the caller's shell (avoids capturing prompt output in process subs).
$2..$N = candidate paths
Arguments¶
- $1 (name): of output array (will be cleared and populated)
shell_scripts::find_root_only¶
Emit shell-script paths that live directly in the repo root (no
subdirectories). Used by .ci/build-docs and .ci/check-shdoc-headers to enumerate
project-root executables such as shellcheck-scripts,
check-scripts, run-install-scripts, run-set-up-scripts, run-tests.
Filters to files whose first line contains a bash/sh/bats shebang
(via shell_scripts::has_shell_shebang). Dotfiles are excluded wholesale — the
* glob does not match them — so .envrc and a root-level .functions.bash
loader never become candidates in the first place.
Function has no arguments.
Exit codes¶
- 0: at least one root-level shell script was emitted
- 1: the repo root holds no shell scripts
Output on stdout¶
- file paths, one per line
shell_scripts::requires_help_flag¶
Return true if a top-level script is required to call
args::handle_help_flag. The call is mandatory on every top-level script
with two exemptions, and both are structural rather than listed: a pass-through
script carries the mandatory pass-through comment, and a standalone script
never sources the function library, so the helper does not exist for it to
call. The library test matches functions.bash rather than any source line —
a misc/ script sourcing ~/.profile is still standalone, while a Docker script
sourcing ${DOCKER_COMPOSE_DIR}/functions.bash gets this repo's helpers
transitively and is not exempt.
Deliberate looseness: pass-through marks two different exemptions —
the help-flag one this predicate wants, and the arg-count-guard one, which a
merely variadic script also carries. Three scripts (mvn-fresh, claude-resume,
sync-flatpaks) carry the arity marker while still owning their own --help, so
this reads them as exempt when they are not. That costs nothing today because
all three call the helper anyway, and erring toward exempt keeps the predicate
free of false positives. Tightening it needs a marker that distinguishes the
two exemptions, which is a convention change rather than a lint change.
Arguments¶
- $1 (file): path to script
Exit codes¶
- 0: the script must call args::handle_help_flag
- 1: the script is exempt as a pass-through or a standalone