pure-bash-bible/manuscript/chapter19.txt

246 lines
4.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OTHER
## Use `read` as an alternative to the `sleep` command
Surprisingly, `sleep` is an external command and not a `bash` built-in.
**CAVEAT:** Requires `bash` 4+
**Example Function:**
```sh
read_sleep() {
# Usage: read_sleep 1
# read_sleep 0.2
read -rt "$1" <> <(:) || :
}
```
**Example Usage:**
```shell
read_sleep 1
read_sleep 0.1
read_sleep 30
```
For performance-critical situations, where it is not economic to open and close an excessive number of file descriptors, the allocation of a file descriptor may be done only once for all invocations of `read`:
(See the generic original implementation at https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever)
```shell
exec {sleep_fd}<> <(:)
while some_quick_test; do
# equivalent of sleep 0.001
read -t 0.001 -u $sleep_fd
done
```
## Check if a program is in the user's PATH
```shell
# There are 3 ways to do this and either one can be used.
type -p executable_name &>/dev/null
hash executable_name &>/dev/null
command -v executable_name &>/dev/null
# As a test.
if type -p executable_name &>/dev/null; then
# Program is in PATH.
fi
# Inverse.
if ! type -p executable_name &>/dev/null; then
# Program is not in PATH.
fi
# Example (Exit early if program is not installed).
if ! type -p convert &>/dev/null; then
printf '%s\n' "error: convert is not installed, exiting..."
exit 1
fi
```
## Get the current date using `strftime`
Bashs `printf` has a built-in method of getting the date which can be used in place of the `date` command.
**CAVEAT:** Requires `bash` 4+
**Example Function:**
```sh
date() {
# Usage: date "format"
# See: 'man strftime' for format.
printf "%($1)T\\n" "-1"
}
```
**Example Usage:**
```shell
# Using above function.
$ date "%a %d %b - %l:%M %p"
Fri 15 Jun - 10:00 AM
# Using printf directly.
$ printf '%(%a %d %b - %l:%M %p)T\n' "-1"
Fri 15 Jun - 10:00 AM
# Assigning a variable using printf.
$ printf -v date '%(%a %d %b - %l:%M %p)T\n' '-1'
$ printf '%s\n' "$date"
Fri 15 Jun - 10:00 AM
```
## Get the username of the current user
**CAVEAT:** Requires `bash` 4.4+
```shell
$ : \\u
# Expand the parameter as if it were a prompt string.
$ printf '%s\n' "${_@P}"
black
```
## Generate a UUID V4
**CAVEAT**: The generated value is not cryptographically secure.
**Example Function:**
```sh
uuid() {
# Usage: uuid
C="89ab"
for ((N=0;N<16;++N)); do
B="$((RANDOM%256))"
case "$N" in
6) printf '4%x' "$((B%16))" ;;
8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;;
3|5|7|9)
printf '%02x-' "$B"
;;
*)
printf '%02x' "$B"
;;
esac
done
printf '\n'
}
```
**Example Usage:**
```shell
$ uuid
d5b6c731-1310-4c24-9fe3-55d556d44374
```
## Progress bars
This is a simple way of drawing progress bars without needing a for loop
in the function itself.
**Example Function:**
```sh
bar() {
# Usage: bar 1 10
# ^----- Elapsed Percentage (0-100).
# ^-- Total length in chars.
((elapsed=$1*$2/100))
# Create the bar with spaces.
printf -v prog "%${elapsed}s"
printf -v total "%$(($2-elapsed))s"
printf '%s\r' "[${prog// /-}${total}]"
}
```
**Example Usage:**
```shell
for ((i=0;i<=100;i++)); do
# Pure bash micro sleeps (for the example).
(:;:) && (:;:) && (:;:) && (:;:) && (:;:)
# Print the bar.
bar "$i" "10"
done
printf '\n'
```
## Get the list of functions in a script
```sh
get_functions() {
# Usage: get_functions
IFS=$'\n' read -d "" -ra functions < <(declare -F)
printf '%s\n' "${functions[@]//declare -f }"
}
```
## Bypass shell aliases
```shell
# alias
ls
# command
# shellcheck disable=SC1001
\ls
```
## Bypass shell functions
```shell
# function
ls
# command
command ls
```
## Run a command in the background
This will run the given command and keep it running, even after the terminal or SSH connection is terminated. All output is ignored.
```sh
bkr() {
(nohup "$@" &>/dev/null &)
}
bkr ./some_script.sh # some_script.sh is now running in the background
```
## Capture the return value of a function without command substitution
**CAVEAT:** Requires `bash` 4+
This uses local namerefs to avoid using `var=$(some_func)` style command substitution for function output capture.
```sh
to_upper() {
local -n ptr=${1}
ptr=${ptr^^}
}
foo="bar"
to_upper foo
printf "%s\n" "${foo}" # BAR
```
<!-- CHAPTER END -->