Improve build option parsing for scripts
See original GitHub issueIf this is implemented the benefits are:
- not necessary to specify the options in order
- if the option requires and argument, warn and exit
- if the option was not specified, use default values
- if option value is not withing the range, warn and exit
I did this one example for the build_sdcard.sh.
$ sh build_sdcard.sh
build_sdcard.sh [--option <argument>]
Options:
-i, --interaction [0|1] interaction before proceeding with exection (default: 0)
-f, --fatpack [0|1] fatpack mode (default: 0)
-u, --github-user [rootzoll|other] github user to be checked from the repo (default: rootzoll)
-b, --branch [v1.7|v1.8] branch to be built on (default: v1.7)
-d, --display [lcd|hdmi|headless] display class (default: lcd)
-t, --tweak-boot-drive [0|1] tweak boot drives (default: 1)
-w, --wifi-region [US|GB|other] wifi iso code (default: US)
Notes:
all options, long and short accept --opt=value mode also
[0|1] can also be referenced as [false|true]
$ sh build_sdcard.sh -i 1 -f 1 -u nyxnor -b v1.6 -t 0 -w GB
interaction=1
fatpack=1
github_user=nyxnor
branch=v1.6
display=lcd
tweak_boot_drive=0
wifi_region=GB
$ sh build_sdcard.sh -i
build_sdcard.sh: Option '-i' requires an argument.
$ sh build_sdcard.sh -i 2
build_sdcard.sh: Option '--interaction' cannot be '2'! It can only be: 0 1 false true.
$ sh build_sdcard.sh -i 1 -f 1
interaction=1
fatpack=1
github_user=rootzoll
branch=v1.7
display=lcd
tweak_boot_drive=true
wifi_region=US
$ sh build_sdcard.sh --interaction 1 --fatpack=1
interaction=1
fatpack=1
github_user=rootzoll
branch=v1.7
display=lcd
tweak_boot_drive=true
wifi_region=US
#!/usr/bin/env sh
#set -x
me="${0##/*}"
nocolor="\033[0m"
red="\033[31m"
## default user message
error_msg(){ printf %s"${red}${me}: ${1}${nocolor}\n"; exit 1; }
## usage as a function be be called whenever there is a huge mistake on the options
usage(){
printf %s"${me} [--option <argument>]
Options:
-i, --interaction [0|1] interaction before proceeding with exection (default: 0)
-f, --fatpack [0|1] fatpack mode (default: 0)
-u, --github-user [rootzoll|other] github user to be checked from the repo (default: rootzoll)
-b, --branch [v1.7|v1.8] branch to be built on (default: v1.7)
-d, --display [lcd|hdmi|headless] display class (default: lcd)
-t, --tweak-boot-drive [0|1] tweak boot drives (default: 1)
-w, --wifi-region [US|GB|other] wifi iso code (default: US)
Notes:
all options, long and short accept --opt=value mode also
[0|1] can also be referenced as [false|true]
"
exit 1
}
[ -z "${1}" ] && usage
## assign_value variable_name "${opt}"
## it strips the dashes and assign the clean value to the variable
## assign_value status --on IS status=on
## variable_name is the name you want it to have
## $opt being options with single or double dashes that don't require arguments
assign_value(){
case "${2}" in
--*) value="${2#--}";;
-*) value="${2#-}";;
*) value="${2}"
esac
## Escaping quotes is needed because else if will fail if the argument is quoted
# shellcheck disable=SC2140
eval "${1}"="\"${value}\""
}
## get_arg variable_name "${opt}" "${arg}"
## get_arg service --service ssh
## variable_name is the name you want it to have
## $opt being options with single or double dashes
## $arg is requiring and argument, else it fails
## assign_value "${1}" "${3}" means it is assining the argument ($3) to the variable_name ($1)
get_arg(){
case "${3}" in
""|-*) error_msg "Option '${2}' requires an argument.";;
esac
assign_value "${1}" "${3}"
}
## hacky getopts
## 1. if the option requires argument, and the option is preceeded by single or double dash and it
## can be it can be specified with '-s=ssh' or '-s ssh' or '--service=ssh' or '--service ssh'
## use: get_arg variable_name "${opt}" "${arg}"
## 2. if a bunch of options that does different things are to be assigned to the same variable
## and the option is preceeded by single or double dash use: assign_value variable_name "${opt}"
## as this option does not require argument, specifu $shift_n=1
## 3. if the option does not start with dash and does not require argument, assign to command manually.
while :; do
case "${1}" in
-*=*) opt="${1%=*}"; arg="${1#*=}"; shift_n=1;;
-*) opt="${1}"; arg="${2}"; shift_n=2;;
*) opt="${1}"; arg="${2}"; shift_n=1;;
esac
case "${opt}" in
-i|-i=*|--interaction|--interaction=*) get_arg interaction "${opt}" "${arg}";;
-f|-f=*|--fatpack|--fatpack=*) get_arg fatpack "${opt}" "${arg}";;
-u|-u=*|--github-user|--github-user=*) get_arg github_user "${opt}" "${arg}";;
-b|-b=*|--branch|--branch=*) get_arg branch "${opt}" "${arg}";;
-d|-d=*|--display|--display=*) get_arg display "${opt}" "${arg}";;
-t|-t=*|--tweak-boot-drive|--tweak-boot-drive=*) get_arg tweak_boot_drive "${opt}" "${arg}";;
-w|-w=*|--wifi-region|--wifi-region=*) get_arg wifi_region "${opt}" "${arg}";;
"") break;;
*) error_msg "Invalid option: ${opt}";;
esac
shift "${shift_n}"
done
## if there is a limited option, check if the value of variable is within this range
## $ range_argument variable_name possible_value_1 possible_value_2
range_argument(){
name="${1}"
eval var='$'"${1}"
shift
if [ -n "${var:-}" ]; then
success=0
for tests in "${@}"; do
[ "${var}" = "${tests}" ] && success=1
done
[ ${success} -ne 1 ] && error_msg "Option '--${name}' cannot be '${var}'! It can only be: ${*}."
fi
}
## use default values for variables if empty
: "${interaction:=false}"
range_argument interaction "0" "1" "false" "true"
: "${fatpack:=false}"
range_argument fatpack "0" "1" "false" "true"
: "${github_user:=rootzoll}"
curl -s "https://api.github.com/repos/${github_user}/raspiblitz" | grep -q "\"message\": \"Not Found\"" && error_msg "Repository 'raspiblitz' not found for user '${github_user}"
: "${branch:=v1.7}"
curl -s "https://api.github.com/repos/${github_user}/raspiblitz/branches/${branch}" | grep -q "\"message\": \"Branch not found\"" && error_msg "Repository 'raspiblitz' for user '${github_user}' does not contain branch '${branch}'"
: "${display:=lcd}"
range_argument display "lcd" "hdmi" "headless"
: "${tweak_boot_drive:=true}"
range_argument tweak_boot_drive "0" "1" "false" "true"
: "${wifi_region:=US}"
for key in interaction fatpack github_user branch display tweak_boot_drive wifi_region; do
eval val='$'"${key}"
[ -n "${val}" ] && printf '%s\n' "${key}=${val}"
done
exit 1
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (9 by maintainers)
Top Results From Across the Web
How JavaScript works: Optimizing for parsing efficiency
Finally, you can improve parse efficiency by sidestepping parsing entirely. One option for server-side compilation is WebAssembly (WASM).
Read more >JavaScript Start-up Optimization - web.dev
Keep your network transmission and parse/compile cost for JavaScript low to ensure pages get interactive quickly.
Read more >Option parser in bash more evolved than getopts
Its a code generator that creates a parser script that supports long and short options, and creates help documentation automatically.
Read more >Adding arguments and options to your Bash scripts - Red Hat
Another is the use of options and option arguments. This article explores these two methods for getting data into the script and controlling...
Read more >Three ways to parse arguments in your Python code
The first option is to use argparse which is a popular Python module specialized in command-line parsing. Another way is to read the...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

it is better to be a test conditional than simply comparing if the string if empty, cause it is never gonna be an empty string anymore https://github.com/rootzoll/raspiblitz/blob/3d12c6abebc9275cf7ec950378ec0d795d09c791/build_sdcard.sh#L140
I suggest building an function that converts the value from
1totrueand0tofalse.I changed the variables names, just be alert