507 lines
24 KiB
Org Mode
507 lines
24 KiB
Org Mode
* sf -- script framework
|
|
|
|
[[./images/logo.png]]
|
|
|
|
/script framework/ can be used to simplify and beautify Bash scripts.
|
|
It provides:
|
|
|
|
- Argument parsing
|
|
- Usage output
|
|
- Input functions
|
|
- Output functions
|
|
- Text formatting variables
|
|
|
|
All just by declaring some variables and sourcing it.
|
|
Or keep your scripts self-contained and include it as an oneliner.
|
|
|
|
The usage is pretty self-explanatory once you have seen it.
|
|
If you're curious and don't want to read through the documentation, head directly to the [[#examples][examples]].
|
|
|
|
-----
|
|
|
|
Here is the oneliner version of /sf/ which was created with [[https://github.com/precious/bash_minifier][this]] tool:
|
|
|
|
#+begin_src sh
|
|
# sf -- script framework (https://github.com/Deleh/sf)
|
|
sftrs=$'\e[0m';sftbf=$'\e[1m';sftdim=$'\e[2m';sftul=$'\e[4m';sftblk=$'\e[5m';sftinv=$'\e[7m';sfthdn=$'\e[8m';sftclr=$'\e[1A\e[K';sftk=$'\e[30m';sftr=$'\e[31m';sftg=$'\e[32m';sfty=$'\e[33m';sftb=$'\e[34m';sftm=$'\e[35m';sftc=$'\e[36m';sftw=$'\e[97m';function sferr { echo -e "${sftbf}${sftr}ERROR${sftrs} $1";[ -z "$2" ]&&exit 1;};function sfwarn { echo -e "${sftbf}${sfty}WARNING${sftrs} $1";};function sfask { if [ -n "$2" ];then echo -ne "$1? [${sftbf}y${sftrs}/${sftbf}N${sftrs}] ";read -r sfin;[[ "$sfin" =~ n|N|^$ ]]&&sfin=false||sfin=true;else echo -ne "$1? [${sftbf}Y${sftrs}/${sftbf}n${sftrs}] ";read -r sfin;[[ "$sfin" =~ y|Y|^$ ]]&&sfin=true||sfin=false;fi;};function sfget { if [ -n "$2" ];then read -r -p "$1 [${sftbf}$2${sftrs}]: " sfin;else read -r -p "$1: " sfin;fi;[ "$sfin" == "" ]&&[ "$2" != "" ]&&sfin="$2";};function _sferr { echo "${sftbf}${sftr}SF PARSE ERROR${sftrs} $1";exit 1;};OLDIFS=$IFS;IFS=";";_sfpargs=();_sfpheads=();_sfpoffset=0;_sfptails=();_sfpusage="";_sfoheads=();_sfooffset=0;_sfotails=();declare -A _sfflags;declare -A _sfargs;sfargs=("${sfargs[@]}" "help;h;Show this help message and exit");for a in "${sfargs[@]}";do _sfsubst=${a//";"};_sfcount="$((${#a} - ${#_sfsubst}))";if [ "$_sfcount" -eq 1 ];then read -r -a _sfparsearr<<<"${a}";[[ " ${_sfpargs[*]} " =~ " ${_sfparsearr[0]} " ]]&&_sferr "${sftbf}${_sfparsearr[0]}${sftrs} is already set: ${sftbf}${a}${sftrs}";_sfpargs+=("${_sfparsearr[0]}");_sfpusage="$_sfpusage ${_sfparsearr[0]}";_sfphead="${_sfparsearr[0]}";[ "${#_sfphead}" -gt "${_sfpoffset}" ]&&_sfpoffset="${#_sfphead}";_sfpheads+=("$_sfphead");_sfptails+=("${_sfparsearr[1]}");elif [ "$_sfcount" -eq 2 ];then read -r -a _sfparsearr<<<"${a}";[ -n "${_sfflags["--${_sfparsearr[0]}"]}" ]&&_sferr "${sftbf}${_sfparsearr[0]}${sftrs} is already set: ${sftbf}${a}${sftrs}";_sfflags["--${_sfparsearr[0]}"]="${_sfparsearr[0]}";[ -n "${_sfflags["-${_sfparsearr[1]}"]}" ]&&_sferr "${sftbf}${_sfparsearr[1]}${sftrs} is already set: ${sftbf}${a}${sftrs}";_sfflags["-${_sfparsearr[1]}"]="${_sfparsearr[0]}";declare "${_sfparsearr[0]//-/_}"=false;_sfohead="-${_sfparsearr[1]}, --${_sfparsearr[0]}";[ "${#_sfohead}" -gt "${_sfooffset}" ]&&_sfooffset="${#_sfohead}";_sfoheads+=("$_sfohead");_sfotails+=("${_sfparsearr[2]}");elif [ "$_sfcount" -eq 4 ];then read -r -a _sfparsearr<<<"${a}";[ -n "${_sfargs["--${_sfparsearr[0]}"]}" ]&&_sferr "${sftbf}${_sfparsearr[0]}${sftrs} is already set: ${sftbf}${a}${sftrs}";_sfargs["--${_sfparsearr[0]}"]="${_sfparsearr[0]}";[ -n "${_sfargs["-${_sfparsearr[1]}"]}" ]&&_sferr "${sftbf}${_sfparsearr[1]}${sftrs} is already set: ${sftbf}${a}${sftrs}";_sfargs["-${_sfparsearr[1]}"]="${_sfparsearr[0]}";declare "${_sfparsearr[0]//-/_}"="${_sfparsearr[3]}";_sfohead="-${_sfparsearr[1]}, --${_sfparsearr[0]} ${_sfparsearr[2]}";[ "${#_sfohead}" -gt "${_sfooffset}" ]&&_sfooffset="${#_sfohead}";_sfoheads+=("$_sfohead");[ "${_sfparsearr[3]}" != "" ]&&_sfotails+=("${_sfparsearr[4]} (default: ${_sfparsearr[3]})")||_sfotails+=("${_sfparsearr[4]}");else _sferr "Wrong argument declaration: ${sftbf}${a}${sftrs}";fi;done;_sfeheads=();_sfetails=();_sfeoffset=0;for e in "${sfexamples[@]}";do _sfsubst=${e//";"};_sfcount="$((${#e} - ${#_sfsubst}))";if [ "$_sfcount" -eq 1 ];then read -r -a _sfparsearr<<<"${e}";_sfehead="${_sfparsearr[0]}";[ "${#_sfehead}" -gt "${_sfeoffset}" ]&&_sfeoffset="${#_sfehead}";_sfeheads+=("$_sfehead");_sfetails+=("${_sfparsearr[1]}");else _sferr "Wrong example declaration: ${sftbf}${e}${sftrs}";fi;done;IFS=$OLDIFS;[ "$sfparr" == true ]&&[ "${#_sfpargs[@]}" == 0 ]&&_sferr "At least one positional argument must be used with ${sftbf}sfparr${sftrs}";[ "$sfparr" == true ]&&_sfpusage="${_sfpusage% *} [${_sfpusage##* } ...]";_sfpoffset=$(("_sfpoffset" + 3));_sfooffset=$(("_sfooffset" + 3));_sfeoffset=$(("_sfeoffset" + 3));_sfwidth=$(stty size|cut -d ' ' -f 2);_sfpdesc="";for i in "${!_sfptails[@]}";do _sfptail="${_sfptails[$i]}";if [ "$((${#_sfptail} + _sfpoffset))" -gt "$_sfwidth" ];then _sftmpwidth="$((_sfwidth - _sfpoffset))";_sftmpwidth=$(echo -e "${_sftmpwidth}\n1"|sort -nr|head -n 1);_sfptail=$(echo "$_sfptail"|fold -s -w "$_sftmpwidth");_sfptail="${_sfptail//$' \n'/$'\n;'}";fi;_sfpdesc="${_sfpdesc} ${_sfpheads[$i]};${_sfptail}\n";done;_sfodesc="";for i in "${!_sfotails[@]}";do _sfotail="${_sfotails[$i]}";if [ "$((${#_sfotail} + _sfooffset))" -gt "$_sfwidth" ];then _sftmpwidth="$((_sfwidth - _sfooffset))";_sftmpwidth=$(echo -e "${_sftmpwidth}\n1"|sort -nr|head -n 1);_sfotail=$(echo "$_sfotail"|fold -s -w "$_sftmpwidth");_sfotail="${_sfotail//$' \n'/$'\n;'}";fi;_sfodesc="${_sfodesc} ${_sfoheads[$i]};${_sfotail}\n";done;_sfexamples="";for i in "${!_sfetails[@]}";do _sfetail="${_sfetails[$i]}";if [ "$((${#_sfetail} + _sfeoffset))" -gt "$_sfwidth" ];then _sftmpwidth="$((_sfwidth - _sfeoffset))";_sftmpwidth=$(echo -e "${_sftmpwidth}\n1"|sort -nr|head -n 1);_sfetail=$(echo "$_sfetail"|fold -s -w "$_sftmpwidth");_sfetail="${_sfetail//$' \n'/$'\n;'}";fi;_sfexamples="${_sfexamples} ${_sfeheads[$i]};${_sfetail}\n";done;function _sfusage { echo -n "Usage: $(basename "$0") [OPTIONS]";echo -ne "$_sfpusage";echo;[ -n "${sfdesc}" ]&&echo -e "\n$sfdesc"|fold -s -w "$_sfwidth";if [ "$_sfpdesc" != "" ];then echo -e "\nPOSITIONAL ARGUMENTS";echo -e "$_sfpdesc"|column -s ";" -t;fi;if [ "$_sfodesc" != "" ];then echo -e "\nOPTIONS";echo -e "$_sfodesc"|column -s ";" -t;fi;if [ "$_sfexamples" != "" ];then echo -e "\nEXAMPLES";echo -e "$_sfexamples"|column -s ";" -t;fi;[ -n "${sfextra}" ]&&echo -e "\n$sfextra"|fold -s -w "$_sfwidth";exit 0;};for a in "$@";do [ "$a" == "-h" ]||[ "$a" == "--help" ]&&_sfusage;done;for d in "${sfdeps[@]}";do if ! command -v "$d"&>/dev/null;then sferr "Command ${sftbf}${d}${sftrs} not found" 0;_sfdeperr=true;fi;done;[ "$_sfdeperr" == true ]&&exit 1;while(("$#"));do if [ -n "${_sfflags["$1"]}" ];then declare "${_sfflags["$1"]//-/_}"=true;elif [ -n "${_sfargs["$1"]}" ];then if [ -n "$2" ]&&[ "${2:0:1}" != "-" ];then declare "${_sfargs["$1"]//-/_}"="$2";shift;else sferr "Argument for ${sftbf}${1}${sftrs} missing";fi;else if [ "${1:0:1}" == "-" ];then sferr "Unsupported argument/flag ${sftbf}${1}${sftrs}";else if [ "${#_sfpargs[@]}" != 0 ];then declare "${_sfpargs[0]//-/_}"="$1";[ "$sfparr" == true ]&&_sfplast="${_sfpargs[0]//-/_}"&&_sfparr=("$1");_sfpargs=("${_sfpargs[@]:1}");elif [ "$sfparr" == true ];then _sfparr+=("$1");else sferr "Too many positional arguments";fi;fi;fi;shift;done;[ "$sfparr" == true ]&&[ "${#_sfparr[@]}" -gt 0 ]&&read -r -a "${_sfplast?}"<<<"${_sfparr[@]}";[ "$sfparr" == true ]&&[ "${#_sfpargs[@]}" -gt 0 ]&&unset '_sfpargs[${#_sfpargs[@]}-1]';if [ "${#_sfpargs[@]}" -gt 0 ];then for p in "${_sfpargs[@]}";do sferr "Positional argument ${sftbf}${p}${sftrs} missing" 0;done;exit 1;fi;unset a d e i OLDIFS _sfargs _sfehead _sfeheads _sfeoffset _sferr _sfetails _sfexamples _sfflags _sfodesc _sfohead _sfoheads _sfooffset _sfotails _sfpargs _sfparr _sfpdesc _sfphead _sfpheads _sfplast _sfpoffset _sfptails _sfpusage _sftmpwidth _sfusage _sfwidth
|
|
#+end_src
|
|
|
|
** Requirements
|
|
|
|
- At least *Bash 4.x*
|
|
|
|
** Usage
|
|
|
|
The general usage for writing a script with /sf/ is:
|
|
|
|
1. Declare /sf/-variables at the top of your script
|
|
2. Include /sf/
|
|
3. Write your script with already parsed arguments, input functions, output functions and text formatting variables
|
|
|
|
*** 1. /sf/-variables
|
|
|
|
This is the list of variables which can be set *before* including /sf/.
|
|
Everything is optional.
|
|
|
|
| Name | Description | Example |
|
|
|--------------+-----------------------------------------------------------------------------------------------------------------------+-------------------------------------|
|
|
| =sfdesc= | Description of the script | ~sfdesc="This script does nothing"~ |
|
|
| =sfargs= | Array for declaration of arguments, positional arguments and flags. Look below for more information | See [[#sfargs][below]] |
|
|
| =sfparr= | Flag which indicates if the last declared positional argument should be treated as array | ~sfparr=true~ |
|
|
| =sfexamples= | Array for declaration of examples for the usage output. Look below for more information | See also [[#sfexamples][below]] |
|
|
| =sfextra= | Additional usage output | ~sfextra="No copyright"~ |
|
|
| =sfdeps= | Array for declaration of script dependencies. An error is thrown if one ore more of the set command are not available | ~sfdeps=("ffmpeg" "opusinfo")~ |
|
|
|
|
Examples which show the usage of all variables can be found [[#examples][below]] and in the =examples= directory.
|
|
|
|
**** =sfargs=
|
|
:properties:
|
|
:custom_id: sfargs
|
|
:end:
|
|
|
|
This is an array of strings.
|
|
Every string defines an argument, a flag or a positional argument of the script.
|
|
The type is defined by the amount of semicolons in the string.
|
|
|
|
| Type | Declaration order | Example |
|
|
|---------------------+-----------------------------------------------------------------+---------------------------------------------------------|
|
|
| Positional argument | =<name>;<description>= | ~sfargs+=("FILE;File to read")~ |
|
|
| Flag | =<name>;<shorthand>;<description>= | ~sfargs+=("verbose;v;Enable verbose output")~ |
|
|
| Argument | =<name>;<shorthand>;<value_name>;<default_value>;<description>= | ~sfargs+=("text;t;TEXT;done;Print TEXT when finished")~ |
|
|
|
|
The order of declaration defines the order in the usage output.
|
|
|
|
**** =sfexamples=
|
|
:properties:
|
|
:custom_id: sfexamples
|
|
:end:
|
|
|
|
This is also an array of strings.
|
|
Examples are of the form =<command>;<description>= and can be added to /sf/ like this:
|
|
|
|
#+begin_src sh
|
|
sfexamples+=("count 8;Count to eight")
|
|
#+end_src
|
|
|
|
*** 2. Include /sf/
|
|
|
|
There are three methods of including /sf/:
|
|
|
|
1. Grab the /sf/ file from this repo, place it next to your script and source it:
|
|
#+begin_src sh
|
|
source "$(dirname $0)/sf"
|
|
#+end_src
|
|
|
|
2. Copy and paste the *oneliner* from the top of this README
|
|
|
|
3. Source /sf/ from the web for example with =curl=:
|
|
#+begin_src sh
|
|
source <(curl -s https://raw.githubusercontent.com/Deleh/sf/main/sf)
|
|
#+end_src
|
|
*Note* that this adds an online dependency to your script AND that sourcing from a web resource might be a potential security issue.
|
|
The main branch should only be used for testing purposes in this method.
|
|
Replace =main= in the URL with a commit hash to prevent future changes in /sf/ breaking your script.
|
|
|
|
*** 3. Write your script
|
|
|
|
/sf/ deals with missing inputs and handles the parsing of arguments.
|
|
This means that after /sf/ was included *you can be sure that all variables have assigned values*.
|
|
Flags are either =false= or =true=, arguments have a provided value or the default value and positional arguments have a provided value.
|
|
|
|
The values are stored in variables with the name =$<name>=.
|
|
If you declared for example a flag like this:
|
|
|
|
#+begin_src sh
|
|
sfargs+=("verbose;v;Enable verbose output")
|
|
#+end_src
|
|
|
|
Then the variable =$verbose= exists with a value of either =false= or =true=.
|
|
|
|
*Note* that dashes in declared =sfargs= variable names get replaced with underscores.
|
|
|
|
**** Input functions
|
|
|
|
User input can be requested with two functions.
|
|
After calling a function, the user input is provided in the variable =$sfin=.
|
|
|
|
| =sfask= | Takes a string as input and asks for /yes/ or /no/. If an additional argument is provided (doesn't matter what), /no/ will be default. =$sfin= is either =true= or =false= |
|
|
| =sfget= | Takes a string as input and asks for user input. If a second argument is provided, this will be the default if no user input was entered |
|
|
|
|
*Note* that the functions append a colon/question mark to the given string.
|
|
|
|
Look at the [[#greet][greet]] example to see the functions in action.
|
|
|
|
**** Output functions
|
|
|
|
Two output functions are provided which can be used to throw warnings and errors.
|
|
|
|
| =sfwarn= | Takes a string as input and prints a warning |
|
|
| =sferr= | Takes a string as input, prints an error and exits with code 1. If an additional argument is passed (doesn't matter what), it will just throw an error and don't exit |
|
|
|
|
**** Text formatting variables
|
|
|
|
The following text formatting variables can be used to modify the output:
|
|
|
|
| =sftrs= | Reset formatting |
|
|
| =sftbf= | Bold |
|
|
| =sftdim= | Dim |
|
|
| =sftul= | Underlined |
|
|
| =sftblk= | Blinking |
|
|
| =sftinv= | Invert foreground/background |
|
|
| =sfthdn= | Hidden |
|
|
| =sftclr= | Clear the previous line |
|
|
| =sftk= | Black |
|
|
| =sftr= | Red |
|
|
| =sftg= | Green |
|
|
| =sfty= | Yellow |
|
|
| =sftb= | Blue |
|
|
| =sftm= | Magenta |
|
|
| =sftc= | Cyan |
|
|
| =sftw= | White |
|
|
|
|
The variables can be used directly in =echo=, no =-e= needed.
|
|
To echo the word "framework" bold and red use the variables for example like this:
|
|
|
|
#+begin_src sh
|
|
echo "${sftbf}${sftr}framework${sftrs}"
|
|
#+end_src
|
|
|
|
Look at the [[#clear][clear]] example to see some of them in action.
|
|
|
|
** Examples
|
|
:properties:
|
|
:custom_id: examples
|
|
:end:
|
|
|
|
All examples can also be found in the =examples= directory.
|
|
Play around with the /sf/-variables and see what happens.
|
|
|
|
*** Count
|
|
|
|
This example script counts from/to a number and shows the general usage of /sf/-variables:
|
|
|
|
#+begin_src sh
|
|
#!/usr/bin/env bash
|
|
|
|
# ----------------------
|
|
# sf -- script framework
|
|
# ----------------------
|
|
|
|
# Declare sf variables
|
|
sfdesc="A simple counter."
|
|
|
|
sfargs+=("N;Number to count")
|
|
sfargs+=("reverse;r;Count reverse")
|
|
sfargs+=("text;t;TEXT;done;Print TEXT when finished counting")
|
|
|
|
sfexamples+=("count 8;Count to eight")
|
|
sfexamples+=("count -r -t go 3;Count reverse from 3 and print 'go'")
|
|
|
|
sfextra="No copyright at all."
|
|
|
|
# Include sf, this could be replaced with a long oneliner
|
|
source "$(dirname $0)/sf"
|
|
|
|
# ----------------------
|
|
# Actual script
|
|
# ----------------------
|
|
|
|
if [ "$N" -gt 10 ]; then # Use parsed positional argument
|
|
sferr "I can only count to/from 10" # Throw an error and exit
|
|
fi
|
|
|
|
counter="$N" # Use parsed positional argument
|
|
echo -n "$sftbf" # Print everything from here bold
|
|
while [ "$counter" -gt 0 ]; do
|
|
if [ "$reverse" == true ]; then # Use parsed flag
|
|
echo " $counter"
|
|
else
|
|
echo " $(expr $N - $counter + 1)" # Use parsed positional argument
|
|
fi
|
|
counter=$(expr $counter - 1)
|
|
sleep 1
|
|
done
|
|
echo -n "$sftrs" # Reset text formatting
|
|
echo " $text" # Use parsed argument
|
|
#+end_src
|
|
|
|
The usage output of the script is:
|
|
|
|
#+begin_example
|
|
Usage: count [OPTIONS] N
|
|
|
|
A simple counter.
|
|
|
|
POSITIONAL ARGUMENTS
|
|
N Number to count
|
|
|
|
OPTIONS
|
|
-r, --reverse Count reverse
|
|
-t, --text TEXT Print TEXT when finished counting (default: done)
|
|
-h, --help Show this help message and exit
|
|
|
|
EXAMPLES
|
|
count 8 Count to eight
|
|
count -r -t go 3 Count reverse from 3 and print 'go'
|
|
|
|
No copyright at all.
|
|
#+end_example
|
|
|
|
An example call looks like this:
|
|
|
|
#+begin_example
|
|
$ ./count -r -t go 3
|
|
3
|
|
2
|
|
1
|
|
go
|
|
#+end_example
|
|
|
|
*** Clear
|
|
:properties:
|
|
:custom_id: clear
|
|
:end:
|
|
|
|
This script shows the usage of color formatting variables and =$sftclr=:
|
|
|
|
#+begin_src sh
|
|
#!/usr/bin/env bash
|
|
|
|
# ----------------------
|
|
# sf -- script framework
|
|
# ----------------------
|
|
|
|
# Declare sf variables
|
|
sfdesc="Show the usage of color variables and \$sftclr."
|
|
|
|
# Include sf, this could be replaced with a long oneliner
|
|
source "$(dirname $0)/sf"
|
|
|
|
# ----------------------
|
|
# Actual script
|
|
# ----------------------
|
|
|
|
echo -n "${sftbf}" # Output everything from here bold
|
|
echo "${sftr}These" # Red
|
|
sleep 0.5
|
|
echo "${sftm}lines" # Magenta
|
|
sleep 0.5
|
|
echo "${sftb}will" # Blue
|
|
sleep 0.5
|
|
echo "${sftc}delete" # Cyan
|
|
sleep 0.5
|
|
echo "${sftg}themselves" # Green
|
|
sleep 1
|
|
echo "${sfty}now!" # Yellow
|
|
sleep 0.5
|
|
echo -n "${sftclr}${sftclr}${sftclr}${sftclr}${sftclr}${sftclr}" # Clear six lines
|
|
echo "${sftblk}${sftr}T${sftm}a${sftb}d${sftc}a${sftg}a${sfty}!" # Blinking colorful
|
|
echo -n "${sftrs}" # Reset text formatting
|
|
#+end_src
|
|
|
|
The produced usage is:
|
|
|
|
#+begin_example
|
|
Usage: clear [OPTIONS]
|
|
|
|
Show the usage of color variables and $sftclr.
|
|
|
|
OPTIONS
|
|
-h, --help Show this help message and exit
|
|
#+end_example
|
|
|
|
The execution results in this:
|
|
|
|
#+begin_example
|
|
$ ./clear
|
|
Tadaa!
|
|
#+end_example
|
|
|
|
*** Add
|
|
|
|
This script adds numbers and shows the usage of =sfparr=:
|
|
|
|
#+begin_src sh
|
|
#!/usr/bin/env bash
|
|
|
|
# ----------------------
|
|
# sf -- script framework
|
|
# ----------------------
|
|
|
|
# Declare sf variables
|
|
sfdesc="Calculate the sum of multiple numbers."
|
|
|
|
sfargs+=("NUMBERS;Numbers which will be added")
|
|
sfargs+=("verbose;v;Enable verbose output")
|
|
|
|
sfparr=true # Treat the last declared positional argument as array
|
|
|
|
# Include sf, this could be replaced with a long oneliner
|
|
source "$(dirname $0)/sf"
|
|
|
|
# ----------------------
|
|
# Actual script
|
|
# ----------------------
|
|
|
|
sum=0
|
|
|
|
for n in "${NUMBERS[@]}"; do # Use parsed positional argument array
|
|
if [ "$verbose" == true ]; then # Use parsed flag
|
|
echo -n "$sum + $n = "
|
|
fi
|
|
sum="$(expr $sum + $n)"
|
|
if [ "$verbose" == true ]; then # Use parsed flag
|
|
echo "$sftbf$sum$sftrs" # Use text formatting variables
|
|
fi
|
|
done
|
|
|
|
echo "The sum is: $sftbf$sum$sftrs" # Use text formatting variables
|
|
#+end_src
|
|
|
|
And here is the produced usage:
|
|
|
|
#+begin_example
|
|
Usage: add [OPTIONS] [NUMBERS ...]
|
|
|
|
Calculate the sum of multiple numbers.
|
|
|
|
POSITIONAL ARGUMENTS
|
|
NUMBERS Numbers which will be added
|
|
|
|
OPTIONS
|
|
-v, --verbose Enable verbose output
|
|
-h, --help Show this help message and exit
|
|
#+end_example
|
|
|
|
An example call looks like this:
|
|
|
|
#+begin_example
|
|
$ ./add -v 1 2 3 4 5
|
|
0 + 1 = 1
|
|
1 + 2 = 3
|
|
3 + 3 = 6
|
|
6 + 4 = 10
|
|
10 + 5 = 15
|
|
The sum is: 15
|
|
#+end_example
|
|
|
|
*** Greet
|
|
:properties:
|
|
:custom_id: greet
|
|
:end:
|
|
|
|
This example greets a user and asks for the age.
|
|
It shows the usage of input functions:
|
|
|
|
#+begin_src sh
|
|
#!/usr/bin/env bash
|
|
|
|
# ----------------------
|
|
# sf -- script framework
|
|
# ----------------------
|
|
|
|
# Declare sf variables
|
|
sfdesc="Greet a person."
|
|
|
|
sfargs+=("pretty-useless-flag;p;This is a pretty useless flag which is only used to show correct linebreaks of the usage. Change your terminal size and let this print again to see how the output adapts to your window")
|
|
sfargs+=("ask-for-lastname;l;Ask for lastname")
|
|
|
|
# Include sf, this could be replaced with a long oneliner
|
|
source "$(dirname $0)/sf"
|
|
|
|
# ----------------------
|
|
# Actual script
|
|
# ----------------------
|
|
|
|
sfget "Enter your name" # Get input
|
|
echo "Hello ${sfin}!" # Use input
|
|
|
|
if [ "$ask_for_lastname" == true ]; then # Use variable with underscores instead of dashes
|
|
sfget "Enter your lastname" # Get input
|
|
echo "Ah I see, your lastname is ${sfin}" # Use input
|
|
fi
|
|
|
|
sfask "Do you want to tell me your age" # Ask for YES/no
|
|
if [ "$sfin" == true ]; then # Use answer
|
|
sfget "Enter your Age" "80" # Get input with default value
|
|
sfask "Is $sfin really your age" "no" # Use input and ask for yes/NO
|
|
if [ "$sfin" == true ]; then # Use answer
|
|
echo "Great!"
|
|
else
|
|
echo "I knew it!"
|
|
fi
|
|
fi
|
|
#+end_src
|
|
|
|
The produced usage:
|
|
|
|
#+begin_example
|
|
Usage: greet [OPTIONS]
|
|
|
|
Greet a person.
|
|
|
|
OPTIONS
|
|
-p, --pretty-useless-flag This is a pretty useless flag which is only used to
|
|
show correct linebreaks of the usage. Change your
|
|
terminal size and let this print again to see how
|
|
the output adapts to your window
|
|
-l, --ask-for-lastname Ask for lastname
|
|
-h, --help Show this help message and exit
|
|
#+end_example
|
|
|
|
An example call looks like this:
|
|
|
|
#+begin_example
|
|
$ ./greet
|
|
Enter your name: Jane
|
|
Hello Jane!
|
|
Do you want to tell me your age? [Y/n]
|
|
Enter your Age [80]: 75
|
|
Is 75 really your age? [y/N] y
|
|
Great!
|
|
#+end_example
|
|
|
|
*** Throw
|
|
|
|
This example shows the usage of =sfdeps=:
|
|
|
|
#+begin_src sh
|
|
#!/usr/bin/env bash
|
|
|
|
# ----------------------
|
|
# sf -- script framework
|
|
# ----------------------
|
|
|
|
# Declare sf variables
|
|
sfdesc="A script that shows the usage of 'sfdeps'. It should always throw an error."
|
|
|
|
sfdeps=("source" "nonexistent" "alsononexistent" "echo")
|
|
|
|
# Include sf, this could be replaced with a long oneliner
|
|
source "$(dirname $0)/sf"
|
|
|
|
# ----------------------
|
|
# Actual script
|
|
# ----------------------
|
|
|
|
echo "If you see this, the commands 'source', 'nonexistent', 'alsononexistent' and 'echo' are available."
|
|
#+end_src
|
|
|
|
The usage output:
|
|
|
|
#+begin_example
|
|
Usage: throw [OPTIONS]
|
|
|
|
A script that shows the usage of 'sfdeps'. It should always throw an error.
|
|
|
|
OPTIONS
|
|
-h, --help Show this help message and exit
|
|
#+end_example
|
|
|
|
And the execution:
|
|
|
|
#+begin_example
|
|
$ ./throw
|
|
ERROR Command nonexistent not found
|
|
ERROR Command alsononexistent not found
|
|
#+end_example
|