Skip to content

Commit 2010a64

Browse files
author
Wes Dean
committed
Add overview / usage documentation generator
1 parent a79c88c commit 2010a64

File tree

1 file changed

+107
-24
lines changed

1 file changed

+107
-24
lines changed

shell_script_template.bash

+107-24
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@
1515
## 8. automagic help / usage generation
1616
## @author Wes Dean
1717

18-
1918
set -euo pipefail
2019

20+
2121
## @var SCRIPT_PATH
2222
## @brief path to where the script lives
2323
declare SCRIPT_PATH
2424
# shellcheck disable=SC2034
2525
SCRIPT_PATH="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd -P)"
2626

27+
2728
## @var DEFAULT_WORD
2829
## @brief default value for the 'word' CLI parameter
29-
declare -i DEFAULT_WORD
30+
declare DEFAULT_WORD
3031
# shellcheck disable=SC2034
3132
DEFAULT_WORD="hello"
3233

3334

34-
3535
## @fn die
3636
## @brief receive a trapped error and display helpful debugging details
3737
## @details
@@ -59,44 +59,127 @@ die() {
5959
exit 1
6060
}
6161

62-
trap die ERR
63-
6462

63+
## @fn display_usage
64+
## @brief display some auto-generated usage information
65+
## @details
66+
## This will take two passes over the script -- one to generate
67+
## an overview based on everything between the @file tag and the
68+
## first blank line and another to scan through getopts options
69+
## to extract some hints about how to use the tool.
70+
## @retval 0 if the extraction was successful
71+
## @retval 1 if there was a problem running the extraction
6572
## @par Example
6673
## @code
67-
## # set values from their defaults
68-
## word="${DEFAULT_WORD}"
69-
##
70-
## # process long options
7174
## for arg in "$@" ; do
7275
## shift
7376
## case "$arg" in
74-
## '--word') set -- "$@" "-w" ;;
75-
## '--help') set -- "$@" "-h" ;;
77+
## '--word') set -- "$@" "-w" ;; ##- see -w
78+
## '--help') set -- "$@" "-h" ;; ##- see -h
7679
## *) set -- "$@" "$arg" ;;
7780
## esac
7881
## done
7982
##
8083
## # process short options
8184
## OPTIND=1
82-
## while getopts "w:h" opt ; do
83-
## case "$opt" in
84-
## 'w') word="$OPTARG" ;;
85-
## 'h') display_usage ; exit 0 ;;
86-
## *) echo "Invalid option" ; display_usage ; exit 1 ;;
87-
## esac
88-
## done
85+
###
8986
##
90-
## shift "$((OPTIND - 1))
91-
##
92-
## # Process positional arguments
93-
## for file in "$@" ; do
94-
## printf "%s" "$file"
87+
## while getopts "w:h" option ; do
88+
## case "$option" in
89+
## w ) word="$OPTARG" ;; ##- set the word value
90+
## h ) display_usage ; exit 0 ;;
91+
## * ) printf "Invalid option '%s'" "$option" 2>&1 ; display_usage 1>&2 ; exit 1 ;;
92+
## esac
9593
## done
9694
## @endcode
95+
display_usage() {
96+
local overview
97+
overview="$(sed -Ene '
98+
/^[[:space:]]*##[[:space:]]*@file/,${/^[[:space:]]*$/q}
99+
s/[[:space:]]*@author/author:/
100+
s/^[[:space:]]*##([[:space:]]*@[^[[:space:]]*[[:space:]]*)*//p' < "$0")"
101+
102+
local usage
103+
usage="$(
104+
(
105+
sed -Ene "s/^[[:space:]]*(['\"])([[:alnum:]]*)\1[[:space:]]*\).*##-[[:space:]]*(.*)/\-\2\t\t: \3/p" < "$0"
106+
sed -Ene "s/^[[:space:]]*(['\"])([-[:alnum:]]*)*\1[[:space:]]*\)[[:space:]]*set[[:space:]]*--[[:space:]]*(['\"])[@$]*\3[[:space:]]*(['\"])(-[[:alnum:]])\4.*##-[[:space:]]*(.*)/\2\t\t: \6/p" < "$0"
107+
) | sort --ignore-case)"
108+
109+
if [ -n "$overview" ] ; then
110+
printf "Overview\n%s\n" "$overview"
111+
fi
112+
113+
if [ -n "$usage" ] ; then
114+
printf "\nUsage:\n%s\n" "$usage"
115+
fi
116+
}
117+
118+
119+
## @fn main()
120+
## @brief This is the main program loop.
121+
## @details
122+
## This is where the logic for the program lives; it's
123+
## called when the script is run as a script (i.e., not
124+
## when it's sourced or included).
125+
main() {
126+
127+
trap die ERR
128+
129+
130+
###
131+
### set values from their defaults here
132+
###
97133

98134

135+
word="${DEFAULT_WORD}"
99136

100137

101-
[[ "$0" == "${BASH_SOURCE[0]}" ]] && main "$@"
138+
###
139+
### process long options here
140+
###
141+
142+
143+
for arg in "$@" ; do
144+
shift
145+
case "$arg" in
146+
'--word') set -- "$@" "-w" ;; ##- see -w
147+
'--help') set -- "$@" "-h" ;; ##- see -h
148+
*) set -- "$@" "$arg" ;;
149+
esac
150+
done
151+
152+
153+
###
154+
### process short options here
155+
###
156+
157+
158+
OPTIND=1
159+
while getopts "w:h" opt ; do
160+
case "$opt" in
161+
'w' ) word="$OPTARG" ;; ##- set the word to be processed
162+
'h' ) display_usage ; exit 0 ;; ##- view the help documentation
163+
*) printf "Invalid option '%s'" "$opt" 1>&2 ; display_usage 1>&2 ; exit 1 ;;
164+
esac
165+
done
166+
167+
shift "$((OPTIND - 1))"
168+
169+
# Process positional arguments
170+
for file in "$@" ; do
171+
printf "%s" "$file"
172+
done
173+
174+
175+
###
176+
### program logic goes here
177+
###
178+
179+
echo "$word"
180+
181+
}
182+
102183

184+
# if we're not being sourced and there's a function named `main`, run it
185+
[[ "$0" == "${BASH_SOURCE[0]}" ]] && [ "$(type -t "main")" = "function" ] && main "$@"

0 commit comments

Comments
 (0)