Add `_urlencode` and `_newest` and better docs

This commit is contained in:
rwxrob 2021-08-31 09:47:57 -04:00
parent dae44446b9
commit 39e386700a
No known key found for this signature in database
GPG Key ID: 1CCACEDD2F65578E
2 changed files with 176 additions and 60 deletions

100
README.md
View File

@ -11,20 +11,6 @@ gh repo create rwxrob/mycmd -p rwxrob/template-bash-command
This `cmd` inside can then be renamed and finished. This `cmd` inside can then be renamed and finished.
Obviously, not all of this is needed for many Bash scripts. Just remove
what you do not need or want. If you want to keep a command but hide it
from users just add another underscore to the prefix which turns it into
a hidden command, which will not be included in help documentation and
tab completion, but will still be there. The `readme` command (which
generates this `README.md` file is a good candidate for this.)
Be sure to check out the builtin and utility functions. Some of these
can be removed as well if you really want.
The `_initialize` function is meant to put initialization code at the
beginning of the script to be found easily even though it is called at
the bottom of the script (as bash requires).
## Naming Conventions ## Naming Conventions
* Name repos containing single bash commands with `cmd-` * Name repos containing single bash commands with `cmd-`
@ -32,6 +18,76 @@ the bottom of the script (as bash requires).
* Start command functions with `command_` to be completed * Start command functions with `command_` to be completed
* Start command functions with `command__` to not be completed * Start command functions with `command__` to not be completed
If you want to keep a command but hide it from users just add another
underscore to the prefix which turns it into a hidden command, which
will not be included in help documentation and tab completion, but will
still be there.
## Builtins and Utilities
A number of builtin and frequently used utility functions have been
included for convenience. These save developers from adding other
moronic things like `sed` and `awk` subprocesses. Obviously, not all of
this is needed for many Bash scripts. Just remove what you do not need
or want.
### `_initialize`
The `_initialize` function is meant to contain initialization code and
be placed at the beginning of the script to be found easily even though
it is called at the bottom of the script (as bash requires).
### `_have`
Returns true (0) if the first argument exists as an executable in the
current `PATH`. Otherwise, return false (1).
### `_checkdep`
Checks that the first argument exists as an executable in the current
`PATH`. If so, returns true (0). If not, prints a generic error message
in English and returns false (1). The "progressive enhancement" design
principle requires minimal functionality using what is available and
progressively upgrading based on what is detected.
### `_newest`
Uses `ls` to return the newest file or directory in the specified
directory.
### `_trim`
Removes all whitespace (`[:space:]`) from the beginning and ending
of a string without invoking a subprocess.
### `_filter`
Reads the first argument or each line of standard input passing
each individually as the first argument to the calling function one at
a time. The UNIX philosophy requires all commands be filters whenever possible.
### `_buffer`
Reads the first argument or all lines of standard input and then
passes them to the calling function as the first argument. The UNIX philosophy requires all command be filters whenever possible.
### `_reduce`
Takes the name of an array and a bash extended regular expression
and prints only the array entries that match, one to a line suitable for
converting back into an array with `IFS=$n` or just as an in-memory
`grep` replacement.
### `_jsonstr`
Encodes first argument or all standard input into a single line of JSON text. This function depends on the `jq` command.
### `_urlencode`
Encodes the first argument or all standard input using standard URL
encoding suitable for passing to `curl` or whatever. This function has
no external dependencies.
## Dependencies ## Dependencies
Required: Required:
@ -45,7 +101,7 @@ Optional:
## Justification ## Justification
Bash is the dominate shell scripting language and the official default Bash is the dominant shell scripting language and the official default
Linux interactive shell, which reduces cognitive overhead; every command Linux interactive shell, which reduces cognitive overhead; every command
line *is* a line of code that could be put into script as is. Bash line *is* a line of code that could be put into script as is. Bash
scripts are at the core of cloud, containers, and Kubernetes. Bash 4+ scripts are at the core of cloud, containers, and Kubernetes. Bash 4+
@ -170,18 +226,6 @@ to `$PAGER` (default: more).
Also see `readme` and `usage` commands. Also see `readme` and `usage` commands.
## Convert to JSON String
```
cmd json STRING
cmd json <<< STRING
cmd json < FILE
cmd json < <(COMMAND)
```
Converts input into JSON string using `jq` (if found) containing only
escaped (`\n`) line returns.
## Generate `README.md` File ## Generate `README.md` File
``` ```
@ -202,5 +246,5 @@ Displays a summary of usage.
---- ----
*Autogenerated Sun Aug 29 12:18:52 PM EDT 2021* *Autogenerated Tue Aug 31 09:47:12 AM EDT 2021*

136
cmd
View File

@ -31,20 +31,6 @@ gh repo create rwxrob/mycmd -p rwxrob/template-bash-command
This `cmd` inside can then be renamed and finished. This `cmd` inside can then be renamed and finished.
Obviously, not all of this is needed for many Bash scripts. Just remove
what you do not need or want. If you want to keep a command but hide it
from users just add another underscore to the prefix which turns it into
a hidden command, which will not be included in help documentation and
tab completion, but will still be there. The `readme` command (which
generates this `README.md` file is a good candidate for this.)
Be sure to check out the builtin and utility functions. Some of these
can be removed as well if you really want.
The `_initialize` function is meant to put initialization code at the
beginning of the script to be found easily even though it is called at
the bottom of the script (as bash requires).
## Naming Conventions ## Naming Conventions
* Name repos containing single bash commands with `cmd-` * Name repos containing single bash commands with `cmd-`
@ -52,6 +38,76 @@ the bottom of the script (as bash requires).
* Start command functions with `command_` to be completed * Start command functions with `command_` to be completed
* Start command functions with `command__` to not be completed * Start command functions with `command__` to not be completed
If you want to keep a command but hide it from users just add another
underscore to the prefix which turns it into a hidden command, which
will not be included in help documentation and tab completion, but will
still be there.
## Builtins and Utilities
A number of builtin and frequently used utility functions have been
included for convenience. These save developers from adding other
moronic things like `sed` and `awk` subprocesses. Obviously, not all of
this is needed for many Bash scripts. Just remove what you do not need
or want.
### `_initialize`
The `_initialize` function is meant to contain initialization code and
be placed at the beginning of the script to be found easily even though
it is called at the bottom of the script (as bash requires).
### `_have`
Returns true (0) if the first argument exists as an executable in the
current `PATH`. Otherwise, return false (1).
### `_checkdep`
Checks that the first argument exists as an executable in the current
`PATH`. If so, returns true (0). If not, prints a generic error message
in English and returns false (1). The "progressive enhancement" design
principle requires minimal functionality using what is available and
progressively upgrading based on what is detected.
### `_newest`
Uses `ls` to return the newest file or directory in the specified
directory.
### `_trim`
Removes all whitespace (`[:space:]`) from the beginning and ending
of a string without invoking a subprocess.
### `_filter`
Reads the first argument or each line of standard input passing
each individually as the first argument to the calling function one at
a time. The UNIX philosophy requires all commands be filters whenever possible.
### `_buffer`
Reads the first argument or all lines of standard input and then
passes them to the calling function as the first argument. The UNIX philosophy requires all command be filters whenever possible.
### `_reduce`
Takes the name of an array and a bash extended regular expression
and prints only the array entries that match, one to a line suitable for
converting back into an array with `IFS=$'\n'` or just as an in-memory
`grep` replacement.
### `_jsonstr`
Encodes first argument or all standard input into a single line of JSON text. This function depends on the `jq` command.
### `_urlencode`
Encodes the first argument or all standard input using standard URL
encoding suitable for passing to `curl` or whatever. This function has
no external dependencies.
## Dependencies ## Dependencies
Required: Required:
@ -65,7 +121,7 @@ Optional:
## Justification ## Justification
Bash is the dominate shell scripting language and the official default Bash is the dominant shell scripting language and the official default
Linux interactive shell, which reduces cognitive overhead; every command Linux interactive shell, which reduces cognitive overhead; every command
line *is* a line of code that could be put into script as is. Bash line *is* a line of code that could be put into script as is. Bash
scripts are at the core of cloud, containers, and Kubernetes. Bash 4+ scripts are at the core of cloud, containers, and Kubernetes. Bash 4+
@ -224,6 +280,9 @@ command_readme() {
echo -e "----\n\n*Autogenerated $(date)*\n" echo -e "----\n\n*Autogenerated $(date)*\n"
} }
# command_json() { _jsonstr "$@"; }
# command_urlencode() { _urlencode "$@"; }
# -------------------------- config command -------------------------- # -------------------------- config command --------------------------
HELP[config]=' HELP[config]='
@ -377,29 +436,30 @@ _config_dump() {
<(printf "%s\n" "${CONFIG[@]}") <(printf "%s\n" "${CONFIG[@]}")
} }
# --------------------------- json command --------------------------- # ----------------------------- utilities ----------------------------
HELP[json]='
## Convert to JSON String
```
'"$EXE"' json STRING
'"$EXE"' json <<< STRING
'"$EXE"' json < FILE
'"$EXE"' json < <(COMMAND)
```
Converts input into JSON string using `jq` (if found) containing only
escaped (`\\n`) line returns.'
command_json() { _jsonstr "$@"; }
_jsonstr() { _jsonstr() {
_checkdep jq
_buffer "$@" && return $? _buffer "$@" && return $?
jq -MRsc <<< "$1" jq -MRsc <<< "$1"
} }
# ----------------------------- utilities ---------------------------- _urlencode() {
_buffer "$@" && return $?
local string="$1"
local strlen=${#string}
local encoded=""
local pos c o
for ((pos = 0; pos < strlen; pos++)); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9]) o="$c" ;;
*) printf -v o '%%%02x' "'$c'" ;;
esac
encoded+="$o"
done
echo "$encoded"
}
_reduce() { _reduce() {
local -n name="${1:?"name of array required"}" local -n name="${1:?"name of array required"}"
@ -408,6 +468,12 @@ _reduce() {
done < <(printf "%s\n" "${name[@]}") done < <(printf "%s\n" "${name[@]}")
} }
_newest() {
IFS=$'\n'
local -a f=($(ls -1 --color=never -trd ${1:-.}/* 2>/dev/null))
[[ ${#f} > 0 ]] && echo "${f[-1]}"
}
_trim() { _trim() {
local it="${1#"${1%%[![:space:]]*}"}" local it="${1#"${1%%[![:space:]]*}"}"
echo -e "${it%"${it##*[![:space:]]}"}" echo -e "${it%"${it##*[![:space:]]}"}"
@ -415,6 +481,12 @@ _trim() {
_have(){ type "$1" &>/dev/null; } _have(){ type "$1" &>/dev/null; }
_checkdep() {
_have "$1" && return 0
echo "'$EXE' depends on '$1' for this, but not found"
return 1
}
_filter(){ _filter(){
[[ -n "$1" ]] && return 1 [[ -n "$1" ]] && return 1
while IFS= read -ra args; do while IFS= read -ra args; do