Generate Markdown documentation from shell-scripts
Source: comments, followed by declare prefix and assignments (repeatable inline)
Variable: assignment followed by comments
Function: function, followed by comments, followed by local prefix and assignments (repeatable inline)
Comparison with other implementations
- Does not requires extensive documentation (either in a custom format or Javadoc-like)
- Signatures are extracted directly from code (no duplicate signature, in code and docs)
Notes
- Sources may be prefixed by shebang line
- Variables may be prefixed by
declareorexport - Functions may be prefixed by
function - Arguments must be prefixed by
declare,exportorlocal(resumable inline) - Arguments definition stops at first non-assignment
- Functions and variables may be prefixed by
_(excluded) - Arguments may be prefixed by
_(included) - Check
Makefilefor installation
Usage
shdoc [sources...]
Documentation
This document is auto-generated from shell-scripts sources
modifier @
Array variable or variadic argument
modifier =
Constant variable or argument
modifier :
Treat null variable or argument as unset
modifier ?
Error if variable or argument unset
modifier -
Default value if variable or argument unset
Example source code
#!/usr/bin/env bash
# Script utilities (bash specific)
# Recommended shebang is `/usr/bin/env bash` (so `PATH` is used)
# Then source `SCRIPT_SRC` (defaulting to `/usr/local/share/script`)
# Shell options `errexit` and `nounset` are supported and can be enabled
# Fundamental variables
SCRIPT_SRC="${SCRIPT_SRC:-${BASH_SOURCE:?}}"
# Current script library entry path
# Imported and exported from the environment
source script() [L1]
Script utilities (bash specific)
Recommended shebang is /usr/bin/env bash (so PATH is used)
Then source SCRIPT_SRC (defaulting to /usr/local/share/script)
Shell options errexit and nounset are supported and can be enabled
variable SCRIPT_SRC=:- [L8]
Current script library entry path
Imported and exported from the environment
Example source code
function parse_array() {
# Parse string to an array
# Similar to `var=($txt)` but it does respect quotes and escapes
# Similar to `eval var=($txt)` but it does not respect substitutions and expansions
# **Notice**: array is declared using the name provied
local _var="${1:?}"; shift; local _txts="${*?}"; declare -n _var
function parse_array(var:?, txts@?) [L4]
Parse string to an array
Similar to var=($txt) but it does respect quotes and escapes
Similar to eval var=($txt) but it does not respect substitutions and expansions
Notice: array is declared using the name provied
Example source code
TRUE='1'
# Value representing true
# Used by `is_true` and non-null for tests
variable TRUE= [L5]
Value representing true
Used by is_true and non-null for tests
Example source code
function parse_args() {
# Parses script arguments
# - Verifies arguments are supplied (aborting)
# - Assign them to `const_name` variables named as provided
local _args=("$@")
function parse_args(args@) [L4]
Parses script arguments
- Verifies arguments are supplied (aborting)
- Assign them to
const_namevariables named as provided
Example source code
function local_dir() {
# Get specific local directory (and optionally create it if missing)
# Prefix with `sys` or `user` follow by `-` to get relevant variant
# - `conf` = Configuration
# - `log` = Logging
# - `exe` = Executables
# - `ref` = Data (ro)
# - `state` = Data (rw)
# - `tmp` = Data (timed)
# - `run` = Data (session)
local key="${1:?}" gen="${2-${FALSE?}}" path
function local_dir(key:?, gen-) [L4]
Get specific local directory (and optionally create it if missing)
Prefix with sys or user follow by - to get relevant variant
conf= Configurationlog= Loggingexe= Executablesref= Data (ro)state= Data (rw)tmp= Data (timed)run= Data (session)
Example source code
function typescript() {
# Record the std{in,out,err} of a command (including timing and exit code)
# Similar to `script -c $@` but keeping streams separated
# **Warning**: stdin logger remains active briefly after command (stdin may consume writes)
local log="${1:?}"; shift; local cmd=("${@:?}")
function typescript(log:?, cmd@:?) [L26]
Record the std{in,out,err} of a command (including timing and exit code)
Similar to script -c $@ but keeping streams separated
Warning: stdin logger remains active briefly after command (stdin may consume writes)
Example source code
function @~() {
# Terniary command operator
# **Notice**: result evaluation is not short-circuited
local cmd=("${@:?}") true="${2?}" false="${3?}"
function @~(cmd@:?, true?, false?) [L4]
Terniary command operator
Notice: result evaluation is not short-circuited
Example source code
function is_sys() {
# Checks if the current scope is `sys`
function is_sys() [L18]
Checks if the current scope is sys
Example source code
function rsh() {
# Execute a remote command in a non-interactive environment
# Optional options, host, command (concatenated and evaluated)
local opts=("$@") host="${0:?}" cmd="${*:?}"
function rsh(opts@, host:?, cmd@:?) [L10]
Execute a remote command in a non-interactive environment
Optional options, host, command (concatenated and evaluated)
Example source code
function is_abspath() {
# Checks if path is absolute
local path="${1?}"
function is_abspath(path?) [L4]
Checks if path is absolute
Example source code
function atexit() {
# Register code to be run at exit (LIFO order)
# Code runs with the enviroment present at exit (not at register)
# When enabled `SCRIPT_EXIT` contains the script's exit code
# **Notice**: queues and exits are scoped to the current subshell
# **Warning**: uses `trap ... EXIT` (override)
# - Arguments: concatenated and evaluated at exit
# - No arguments: evaluate queue immediately
local _code="$*" _ _last="$?"
function atexit(code@) [L4]
Register code to be run at exit (LIFO order)
Code runs with the enviroment present at exit (not at register)
When enabled SCRIPT_EXIT contains the script’s exit code
Notice: queues and exits are scoped to the current subshell
Warning: uses trap ... EXIT (override)
- Arguments: concatenated and evaluated at exit
- No arguments: evaluate queue immediately
Example source code
function is_int() {
# Checks if value is a valid integer
local val="${1?}"
function is_int(val?) [L4]
Checks if value is a valid integer
Example source code
SCRIPT_ARGS=("$@")
# Effective script's arguments
# Used when functions need access to the script's arguments insted of their own
SCRIPT_PATH="${SCRIPT_PATH:-$(script_path)}"
# Effective script's path base
# Single path componet used to index into script's specific paths
# Imported from the environment
variable SCRIPT_ARGS@ [L5]
Effective script’s arguments
Used when functions need access to the script’s arguments insted of their own
variable SCRIPT_PATH=:- [L9]
Effective script’s path base
Single path componet used to index into script’s specific paths
Imported from the environment