Added introduction.
This commit is contained in:
14
README.md
14
README.md
@@ -14,7 +14,7 @@ src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
The goal of this repository is to document known and unknown methods of
|
The goal of this book is to document known and unknown methods of
|
||||||
doing various tasks using only built-in `bash` features. Using the snippets
|
doing various tasks using only built-in `bash` features. Using the snippets
|
||||||
from this bible can help to remove unneeded dependencies from your scripts
|
from this bible can help to remove unneeded dependencies from your scripts
|
||||||
and in most cases make them that little bit faster. I came across these
|
and in most cases make them that little bit faster. I came across these
|
||||||
@@ -45,6 +45,7 @@ scripts and not full blown utilities.
|
|||||||
|
|
||||||
<!-- vim-markdown-toc GFM -->
|
<!-- vim-markdown-toc GFM -->
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
* [Strings](#strings)
|
* [Strings](#strings)
|
||||||
* [Trim leading and trailing white-space from string](#trim-leading-and-trailing-white-space-from-string)
|
* [Trim leading and trailing white-space from string](#trim-leading-and-trailing-white-space-from-string)
|
||||||
* [Trim all white-space from string and truncate spaces](#trim-all-white-space-from-string-and-truncate-spaces)
|
* [Trim all white-space from string and truncate spaces](#trim-all-white-space-from-string-and-truncate-spaces)
|
||||||
@@ -156,6 +157,17 @@ scripts and not full blown utilities.
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<!-- CHAPTER START -->
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
A collection of pure `bash` alternatives to external processes and programs. The `bash` scripting language is more powerful than people realise and you can accomplish most tasks without the need or dependency of external programs.
|
||||||
|
|
||||||
|
Calling an external process in `bash` is expensive and excessive use will cause a noticeable slowdown. By sticking to built-in methods (*where possible*) your scripts and programs will be faster, require less dependencies and you'll gain a better understanding of the language itself.
|
||||||
|
|
||||||
|
The contents of this book provide a reference for solving the problems encountered when writing programs and scripts in `bash`. The examples are in function format showcasing how to incorporate these solutions into your code.
|
||||||
|
|
||||||
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
<!-- CHAPTER START -->
|
<!-- CHAPTER START -->
|
||||||
# Strings
|
# Strings
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ chapter13.txt
|
|||||||
chapter14.txt
|
chapter14.txt
|
||||||
chapter15.txt
|
chapter15.txt
|
||||||
chapter16.txt
|
chapter16.txt
|
||||||
|
chapter17.txt
|
||||||
|
|||||||
@@ -1,376 +1,10 @@
|
|||||||
# Strings
|
# Introduction
|
||||||
|
|
||||||
## Trim leading and trailing white-space from string
|
A collection of pure `bash` alternatives to external processes and programs. The `bash` scripting language is more powerful than people realise and you can accomplish most tasks without the need or dependency of external programs.
|
||||||
|
|
||||||
This is an alternative to `sed`, `awk`, `perl` and other tools. The
|
Calling an external process in `bash` is expensive and excessive use will cause a noticeable slowdown. By sticking to built-in methods (*where possible*) your scripts and programs will be faster, require less dependencies and you'll gain a better understanding of the language itself.
|
||||||
function below works by finding all leading and trailing white-space and
|
|
||||||
removing it from the start and end of the string. The `:` built-in is used in place of a temporary variable.
|
|
||||||
|
|
||||||
**Example Function:**
|
The contents of this book provide a reference for solving the problems encountered when writing programs and scripts in `bash`. The examples are in function format showcasing how to incorporate these solutions into your code.
|
||||||
|
|
||||||
```sh
|
|
||||||
trim_string() {
|
|
||||||
# Usage: trim_string " example string "
|
|
||||||
: "${1#"${1%%[![:space:]]*}"}"
|
|
||||||
: "${_%"${_##*[![:space:]]}"}"
|
|
||||||
printf '%s\n' "$_"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ trim_string " Hello, World "
|
|
||||||
Hello, World
|
|
||||||
|
|
||||||
$ name=" John Black "
|
|
||||||
$ trim_string "$name"
|
|
||||||
John Black
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Trim all white-space from string and truncate spaces
|
|
||||||
|
|
||||||
This is an alternative to `sed`, `awk`, `perl` and other tools. The
|
|
||||||
function below works by abusing word splitting to create a new string
|
|
||||||
without leading/trailing white-space and with truncated spaces.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# shellcheck disable=SC2086,SC2048
|
|
||||||
trim_all() {
|
|
||||||
# Usage: trim_all " example string "
|
|
||||||
set -f
|
|
||||||
set -- $*
|
|
||||||
printf '%s\n' "$*"
|
|
||||||
set +f
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ trim_all " Hello, World "
|
|
||||||
Hello, World
|
|
||||||
|
|
||||||
$ name=" John Black is my name. "
|
|
||||||
$ trim_all "$name"
|
|
||||||
John Black is my name.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Use regex on a string
|
|
||||||
|
|
||||||
We can use the result of `bash`'s regex matching to replace `sed` for a
|
|
||||||
large number of use-cases.
|
|
||||||
|
|
||||||
**CAVEAT**: This is one of the few platform dependant `bash` features.
|
|
||||||
`bash` will use whatever regex engine is installed on the user's system.
|
|
||||||
Stick to POSIX regex features if aiming for compatibility.
|
|
||||||
|
|
||||||
**CAVEAT**: This example only prints the first matching group. When using
|
|
||||||
multiple capture groups some modification is needed.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
regex() {
|
|
||||||
# Usage: regex "string" "regex"
|
|
||||||
[[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ # Trim leading white-space.
|
|
||||||
$ regex ' hello' '^\s*(.*)'
|
|
||||||
hello
|
|
||||||
|
|
||||||
$ # Validate a hex color.
|
|
||||||
$ regex "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
|
||||||
#FFFFFF
|
|
||||||
|
|
||||||
$ # Validate a hex color (invalid).
|
|
||||||
$ regex "red" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
|
||||||
# no output (invalid)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage in script:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
is_hex_color() {
|
|
||||||
if [[ "$1" =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then
|
|
||||||
printf '%s\n' "${BASH_REMATCH[1]}"
|
|
||||||
else
|
|
||||||
printf '%s\n' "error: $1 is an invalid color."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
read -r color
|
|
||||||
is_hex_color "$color" || color="#FFFFFF"
|
|
||||||
|
|
||||||
# Do stuff.
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Split a string on a delimiter
|
|
||||||
|
|
||||||
This is an alternative to `cut`, `awk` and other tools.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
split() {
|
|
||||||
# Usage: split "string" "delimiter"
|
|
||||||
IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}"
|
|
||||||
printf '%s\n' "${arr[@]}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ split "apples,oranges,pears,grapes" ","
|
|
||||||
apples
|
|
||||||
oranges
|
|
||||||
pears
|
|
||||||
grapes
|
|
||||||
|
|
||||||
$ split "1, 2, 3, 4, 5" ", "
|
|
||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
||||||
|
|
||||||
# Multi char delimiters work too!
|
|
||||||
$ split "hello---world---my---name---is---john" "---"
|
|
||||||
hello
|
|
||||||
world
|
|
||||||
my
|
|
||||||
name
|
|
||||||
is
|
|
||||||
john
|
|
||||||
```
|
|
||||||
|
|
||||||
## Change a string to lowercase
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lower() {
|
|
||||||
# Usage: lower "string"
|
|
||||||
printf '%s\n' "${1,,}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ lower "HELLO"
|
|
||||||
hello
|
|
||||||
|
|
||||||
$ lower "HeLlO"
|
|
||||||
hello
|
|
||||||
|
|
||||||
$ lower "hello"
|
|
||||||
hello
|
|
||||||
```
|
|
||||||
|
|
||||||
## Change a string to uppercase
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
upper() {
|
|
||||||
# Usage: upper "string"
|
|
||||||
printf '%s\n' "${1^^}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ upper "hello"
|
|
||||||
HELLO
|
|
||||||
|
|
||||||
$ upper "HeLlO"
|
|
||||||
HELLO
|
|
||||||
|
|
||||||
$ upper "HELLO"
|
|
||||||
HELLO
|
|
||||||
```
|
|
||||||
|
|
||||||
## Trim quotes from a string
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
trim_quotes() {
|
|
||||||
# Usage: trim_quotes "string"
|
|
||||||
: "${1//\'}"
|
|
||||||
printf '%s\n' "${_//\"}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ var="'Hello', \"World\""
|
|
||||||
$ trim_quotes "$var"
|
|
||||||
Hello, World
|
|
||||||
```
|
|
||||||
|
|
||||||
## Strip all instances of pattern from string
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
strip_all() {
|
|
||||||
# Usage: strip_all "string" "pattern"
|
|
||||||
printf '%s\n' "${1//$2}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ strip_all "The Quick Brown Fox" "[aeiou]"
|
|
||||||
Th Qck Brwn Fx
|
|
||||||
|
|
||||||
$ strip_all "The Quick Brown Fox" "[[:space:]]"
|
|
||||||
TheQuickBrownFox
|
|
||||||
|
|
||||||
$ strip_all "The Quick Brown Fox" "Quick "
|
|
||||||
The Brown Fox
|
|
||||||
```
|
|
||||||
|
|
||||||
## Strip first occurrence of pattern from string
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
strip() {
|
|
||||||
# Usage: strip "string" "pattern"
|
|
||||||
printf '%s\n' "${1/$2}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ strip "The Quick Brown Fox" "[aeiou]"
|
|
||||||
Th Quick Brown Fox
|
|
||||||
|
|
||||||
$ strip "The Quick Brown Fox" "[[:space:]]"
|
|
||||||
TheQuick Brown Fox
|
|
||||||
```
|
|
||||||
|
|
||||||
## Strip pattern from start of string
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lstrip() {
|
|
||||||
# Usage: lstrip "string" "pattern"
|
|
||||||
printf '%s\n' "${1##$2}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ lstrip "The Quick Brown Fox" "The "
|
|
||||||
Quick Brown Fox
|
|
||||||
```
|
|
||||||
|
|
||||||
## Strip pattern from end of string
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
rstrip() {
|
|
||||||
# Usage: rstrip "string" "pattern"
|
|
||||||
printf '%s\n' "${1%%$2}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ rstrip "The Quick Brown Fox" " Fox"
|
|
||||||
The Quick Brown
|
|
||||||
```
|
|
||||||
|
|
||||||
## Check if string contains a sub-string
|
|
||||||
|
|
||||||
**Using a test:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
if [[ "$var" == *sub_string* ]]; then
|
|
||||||
printf '%s\n' "sub_string is in var."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Inverse (substring not in string).
|
|
||||||
if [[ "$var" != *sub_string* ]]; then
|
|
||||||
printf '%s\n' "sub_string is not in var."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This works for arrays too!
|
|
||||||
if [[ "${arr[*]}" == *sub_string* ]]; then
|
|
||||||
printf '%s\n' "sub_string is in array."
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
**Using a case statement:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
case "$var" in
|
|
||||||
*sub_string*)
|
|
||||||
# Do stuff
|
|
||||||
;;
|
|
||||||
|
|
||||||
*sub_string2*)
|
|
||||||
# Do more stuff
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
# Else
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
```
|
|
||||||
|
|
||||||
## Check if string starts with sub-string
|
|
||||||
|
|
||||||
```shell
|
|
||||||
if [[ "$var" == sub_string* ]]; then
|
|
||||||
printf '%s\n' "var starts with sub_string."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Inverse (var doesn't start with sub_string).
|
|
||||||
if [[ "$var" != sub_string* ]]; then
|
|
||||||
printf '%s\n' "var does not start with sub_string."
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
## Check if string ends with sub-string
|
|
||||||
|
|
||||||
```shell
|
|
||||||
if [[ "$var" == *sub_string ]]; then
|
|
||||||
printf '%s\n' "var ends with sub_string."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Inverse (var doesn't start with sub_string).
|
|
||||||
if [[ "$var" != *sub_string ]]; then
|
|
||||||
printf '%s\n' "var does not end with sub_string."
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,130 +1,376 @@
|
|||||||
# Arrays
|
# Strings
|
||||||
|
|
||||||
## Reverse an array
|
## Trim leading and trailing white-space from string
|
||||||
|
|
||||||
Enabling `extdebug` allows access to the `BASH_ARGV` array which stores
|
This is an alternative to `sed`, `awk`, `perl` and other tools. The
|
||||||
the current function’s arguments in reverse.
|
function below works by finding all leading and trailing white-space and
|
||||||
|
removing it from the start and end of the string. The `:` built-in is used in place of a temporary variable.
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
reverse_array() {
|
trim_string() {
|
||||||
# Usage: reverse_array "array"
|
# Usage: trim_string " example string "
|
||||||
shopt -s extdebug
|
: "${1#"${1%%[![:space:]]*}"}"
|
||||||
f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
|
: "${_%"${_##*[![:space:]]}"}"
|
||||||
shopt -u extdebug
|
printf '%s\n' "$_"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ reverse_array 1 2 3 4 5
|
$ trim_string " Hello, World "
|
||||||
5
|
Hello, World
|
||||||
4
|
|
||||||
3
|
|
||||||
2
|
|
||||||
1
|
|
||||||
|
|
||||||
$ arr=(red blue green)
|
$ name=" John Black "
|
||||||
$ reverse_array "${arr[@]}"
|
$ trim_string "$name"
|
||||||
green
|
John Black
|
||||||
blue
|
|
||||||
red
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remove duplicate array elements
|
|
||||||
|
|
||||||
Create a temporary associative array. When setting associative array
|
## Trim all white-space from string and truncate spaces
|
||||||
values and a duplicate assignment occurs, bash overwrites the key. This
|
|
||||||
allows us to effectively remove array duplicates.
|
This is an alternative to `sed`, `awk`, `perl` and other tools. The
|
||||||
|
function below works by abusing word splitting to create a new string
|
||||||
|
without leading/trailing white-space and with truncated spaces.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# shellcheck disable=SC2086,SC2048
|
||||||
|
trim_all() {
|
||||||
|
# Usage: trim_all " example string "
|
||||||
|
set -f
|
||||||
|
set -- $*
|
||||||
|
printf '%s\n' "$*"
|
||||||
|
set +f
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ trim_all " Hello, World "
|
||||||
|
Hello, World
|
||||||
|
|
||||||
|
$ name=" John Black is my name. "
|
||||||
|
$ trim_all "$name"
|
||||||
|
John Black is my name.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use regex on a string
|
||||||
|
|
||||||
|
We can use the result of `bash`'s regex matching to replace `sed` for a
|
||||||
|
large number of use-cases.
|
||||||
|
|
||||||
|
**CAVEAT**: This is one of the few platform dependant `bash` features.
|
||||||
|
`bash` will use whatever regex engine is installed on the user's system.
|
||||||
|
Stick to POSIX regex features if aiming for compatibility.
|
||||||
|
|
||||||
|
**CAVEAT**: This example only prints the first matching group. When using
|
||||||
|
multiple capture groups some modification is needed.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
regex() {
|
||||||
|
# Usage: regex "string" "regex"
|
||||||
|
[[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ # Trim leading white-space.
|
||||||
|
$ regex ' hello' '^\s*(.*)'
|
||||||
|
hello
|
||||||
|
|
||||||
|
$ # Validate a hex color.
|
||||||
|
$ regex "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
||||||
|
#FFFFFF
|
||||||
|
|
||||||
|
$ # Validate a hex color (invalid).
|
||||||
|
$ regex "red" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
||||||
|
# no output (invalid)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage in script:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
is_hex_color() {
|
||||||
|
if [[ "$1" =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then
|
||||||
|
printf '%s\n' "${BASH_REMATCH[1]}"
|
||||||
|
else
|
||||||
|
printf '%s\n' "error: $1 is an invalid color."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read -r color
|
||||||
|
is_hex_color "$color" || color="#FFFFFF"
|
||||||
|
|
||||||
|
# Do stuff.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Split a string on a delimiter
|
||||||
|
|
||||||
|
This is an alternative to `cut`, `awk` and other tools.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
split() {
|
||||||
|
# Usage: split "string" "delimiter"
|
||||||
|
IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}"
|
||||||
|
printf '%s\n' "${arr[@]}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ split "apples,oranges,pears,grapes" ","
|
||||||
|
apples
|
||||||
|
oranges
|
||||||
|
pears
|
||||||
|
grapes
|
||||||
|
|
||||||
|
$ split "1, 2, 3, 4, 5" ", "
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
|
||||||
|
# Multi char delimiters work too!
|
||||||
|
$ split "hello---world---my---name---is---john" "---"
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
my
|
||||||
|
name
|
||||||
|
is
|
||||||
|
john
|
||||||
|
```
|
||||||
|
|
||||||
|
## Change a string to lowercase
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
**CAVEAT:** Requires `bash` 4+
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
remove_array_dups() {
|
lower() {
|
||||||
# Usage: remove_array_dups "array"
|
# Usage: lower "string"
|
||||||
declare -A tmp_array
|
printf '%s\n' "${1,,}"
|
||||||
|
|
||||||
for i in "$@"; do
|
|
||||||
[[ "$i" ]] && IFS=" " tmp_array["${i:- }"]=1
|
|
||||||
done
|
|
||||||
|
|
||||||
printf '%s\n' "${!tmp_array[@]}"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ remove_array_dups 1 1 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5
|
$ lower "HELLO"
|
||||||
1
|
hello
|
||||||
2
|
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
||||||
|
|
||||||
$ arr=(red red green blue blue)
|
$ lower "HeLlO"
|
||||||
$ remove_array_dups "${arr[@]}"
|
hello
|
||||||
red
|
|
||||||
green
|
$ lower "hello"
|
||||||
blue
|
hello
|
||||||
```
|
```
|
||||||
|
|
||||||
## Random array element
|
## Change a string to uppercase
|
||||||
|
|
||||||
|
**CAVEAT:** Requires `bash` 4+
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
random_array_element() {
|
upper() {
|
||||||
# Usage: random_array_element "array"
|
# Usage: upper "string"
|
||||||
local arr=("$@")
|
printf '%s\n' "${1^^}"
|
||||||
printf '%s\n' "${arr[RANDOM % $#]}"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ array=(red green blue yellow brown)
|
$ upper "hello"
|
||||||
$ random_array_element "${array[@]}"
|
HELLO
|
||||||
yellow
|
|
||||||
|
|
||||||
# You can also just pass multiple arguments.
|
$ upper "HeLlO"
|
||||||
$ random_array_element 1 2 3 4 5 6 7
|
HELLO
|
||||||
3
|
|
||||||
|
$ upper "HELLO"
|
||||||
|
HELLO
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cycle through an array
|
## Trim quotes from a string
|
||||||
|
|
||||||
Each time the `printf` is called, the next array element is printed. When
|
**Example Function:**
|
||||||
the print hits the last array element it starts from the first element
|
|
||||||
again.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
arr=(a b c d)
|
trim_quotes() {
|
||||||
|
# Usage: trim_quotes "string"
|
||||||
cycle() {
|
: "${1//\'}"
|
||||||
printf '%s ' "${arr[${i:=0}]}"
|
printf '%s\n' "${_//\"}"
|
||||||
((i=i>=${#arr[@]}-1?0:++i))
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
## Toggle between two values
|
```shell
|
||||||
|
$ var="'Hello', \"World\""
|
||||||
|
$ trim_quotes "$var"
|
||||||
|
Hello, World
|
||||||
|
```
|
||||||
|
|
||||||
This works the same as above, this is just a different use case.
|
## Strip all instances of pattern from string
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
arr=(true false)
|
strip_all() {
|
||||||
|
# Usage: strip_all "string" "pattern"
|
||||||
cycle() {
|
printf '%s\n' "${1//$2}"
|
||||||
printf '%s ' "${arr[${i:=0}]}"
|
|
||||||
((i=i>=${#arr[@]}-1?0:++i))
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ strip_all "The Quick Brown Fox" "[aeiou]"
|
||||||
|
Th Qck Brwn Fx
|
||||||
|
|
||||||
|
$ strip_all "The Quick Brown Fox" "[[:space:]]"
|
||||||
|
TheQuickBrownFox
|
||||||
|
|
||||||
|
$ strip_all "The Quick Brown Fox" "Quick "
|
||||||
|
The Brown Fox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Strip first occurrence of pattern from string
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
strip() {
|
||||||
|
# Usage: strip "string" "pattern"
|
||||||
|
printf '%s\n' "${1/$2}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ strip "The Quick Brown Fox" "[aeiou]"
|
||||||
|
Th Quick Brown Fox
|
||||||
|
|
||||||
|
$ strip "The Quick Brown Fox" "[[:space:]]"
|
||||||
|
TheQuick Brown Fox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Strip pattern from start of string
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lstrip() {
|
||||||
|
# Usage: lstrip "string" "pattern"
|
||||||
|
printf '%s\n' "${1##$2}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ lstrip "The Quick Brown Fox" "The "
|
||||||
|
Quick Brown Fox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Strip pattern from end of string
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rstrip() {
|
||||||
|
# Usage: rstrip "string" "pattern"
|
||||||
|
printf '%s\n' "${1%%$2}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ rstrip "The Quick Brown Fox" " Fox"
|
||||||
|
The Quick Brown
|
||||||
|
```
|
||||||
|
|
||||||
|
## Check if string contains a sub-string
|
||||||
|
|
||||||
|
**Using a test:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
if [[ "$var" == *sub_string* ]]; then
|
||||||
|
printf '%s\n' "sub_string is in var."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inverse (substring not in string).
|
||||||
|
if [[ "$var" != *sub_string* ]]; then
|
||||||
|
printf '%s\n' "sub_string is not in var."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This works for arrays too!
|
||||||
|
if [[ "${arr[*]}" == *sub_string* ]]; then
|
||||||
|
printf '%s\n' "sub_string is in array."
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Using a case statement:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
case "$var" in
|
||||||
|
*sub_string*)
|
||||||
|
# Do stuff
|
||||||
|
;;
|
||||||
|
|
||||||
|
*sub_string2*)
|
||||||
|
# Do more stuff
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
# Else
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
## Check if string starts with sub-string
|
||||||
|
|
||||||
|
```shell
|
||||||
|
if [[ "$var" == sub_string* ]]; then
|
||||||
|
printf '%s\n' "var starts with sub_string."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inverse (var doesn't start with sub_string).
|
||||||
|
if [[ "$var" != sub_string* ]]; then
|
||||||
|
printf '%s\n' "var does not start with sub_string."
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Check if string ends with sub-string
|
||||||
|
|
||||||
|
```shell
|
||||||
|
if [[ "$var" == *sub_string ]]; then
|
||||||
|
printf '%s\n' "var ends with sub_string."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inverse (var doesn't start with sub_string).
|
||||||
|
if [[ "$var" != *sub_string ]]; then
|
||||||
|
printf '%s\n' "var does not end with sub_string."
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,30 @@
|
|||||||
# Traps
|
# Arithmetic
|
||||||
|
|
||||||
Traps allow you to execute code on various signals. In `pxltrm` I'm using traps to redraw the user interface on window resize. Another use case is cleaning up temporary files on script exit.
|
## Simpler syntax to set variables
|
||||||
|
|
||||||
These `trap` lines should be added near the start of your script so any early errors are also caught.
|
|
||||||
|
|
||||||
**NOTE:** For a full list of signals, see `trap -l`.
|
|
||||||
|
|
||||||
|
|
||||||
## Do something on script exit
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Clear screen on script exit.
|
# Simple math
|
||||||
trap 'printf \\e[2J\\e[H\\e[m' EXIT
|
((var=1+2))
|
||||||
|
|
||||||
|
# Decrement/Increment variable
|
||||||
|
((var++))
|
||||||
|
((var--))
|
||||||
|
((var+=1))
|
||||||
|
((var-=1))
|
||||||
|
|
||||||
|
# Using variables
|
||||||
|
((var=var2*arr[2]))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ignore terminal interrupt (CTRL+C, SIGINT)
|
## Ternary tests
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
trap '' INT
|
# Set the value of var to var2 if var2 is greater than var.
|
||||||
```
|
# var: variable to set.
|
||||||
|
# var2>var: Condition to test.
|
||||||
## React to window resize.
|
# ?var2: If the test succeeds.
|
||||||
|
# :var: If the test fails.
|
||||||
```shell
|
((var=var2>var?var2:var))
|
||||||
# Call a function on window resize.
|
|
||||||
trap 'code_here' SIGWINCH
|
|
||||||
```
|
|
||||||
|
|
||||||
## Do something before every command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
trap 'code_here' DEBUG
|
|
||||||
```
|
|
||||||
|
|
||||||
## Do something when a shell function or a sourced file finishes executing
|
|
||||||
|
|
||||||
```shell
|
|
||||||
trap 'code_here' RETURN
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,13 +1,42 @@
|
|||||||
# Performance
|
# Traps
|
||||||
|
|
||||||
## Disable Unicode
|
Traps allow you to execute code on various signals. In `pxltrm` I'm using traps to redraw the user interface on window resize. Another use case is cleaning up temporary files on script exit.
|
||||||
|
|
||||||
If your script doesn't require unicode, you can disable it for a speed boost. Results may vary but I've seen an improvement in Neofetch and some other smaller programs.
|
These `trap` lines should be added near the start of your script so any early errors are also caught.
|
||||||
|
|
||||||
|
**NOTE:** For a full list of signals, see `trap -l`.
|
||||||
|
|
||||||
|
|
||||||
|
## Do something on script exit
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Disable unicode.
|
# Clear screen on script exit.
|
||||||
LC_ALL=C
|
trap 'printf \\e[2J\\e[H\\e[m' EXIT
|
||||||
LANG=C
|
```
|
||||||
|
|
||||||
|
## Ignore terminal interrupt (CTRL+C, SIGINT)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
trap '' INT
|
||||||
|
```
|
||||||
|
|
||||||
|
## React to window resize.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Call a function on window resize.
|
||||||
|
trap 'code_here' SIGWINCH
|
||||||
|
```
|
||||||
|
|
||||||
|
## Do something before every command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
trap 'code_here' DEBUG
|
||||||
|
```
|
||||||
|
|
||||||
|
## Do something when a shell function or a sourced file finishes executing
|
||||||
|
|
||||||
|
```shell
|
||||||
|
trap 'code_here' RETURN
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,51 +1,13 @@
|
|||||||
# Obsolete Syntax
|
# Performance
|
||||||
|
|
||||||
## Shebang
|
## Disable Unicode
|
||||||
|
|
||||||
Use `#!/usr/bin/env bash` instead of `#!/bin/bash`.
|
If your script doesn't require unicode, you can disable it for a speed boost. Results may vary but I've seen an improvement in Neofetch and some other smaller programs.
|
||||||
|
|
||||||
- The former searches the user's `PATH` to find the `bash` binary.
|
|
||||||
- The latter assumes it is always installed to `/bin/` which can cause issues.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Right:
|
# Disable unicode.
|
||||||
|
LC_ALL=C
|
||||||
#!/usr/bin/env bash
|
LANG=C
|
||||||
|
|
||||||
# Wrong:
|
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
```
|
|
||||||
|
|
||||||
## Command Substitution
|
|
||||||
|
|
||||||
Use `$()` instead of `` ` ` ``.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Right.
|
|
||||||
var="$(command)"
|
|
||||||
|
|
||||||
# Wrong.
|
|
||||||
var=`command`
|
|
||||||
|
|
||||||
# $() can easily be nested whereas `` cannot.
|
|
||||||
var="$(command "$(command)")"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Function Declaration
|
|
||||||
|
|
||||||
Don't use the `function` keyword, it reduces compatibility with older versions of `bash`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Right.
|
|
||||||
do_something() {
|
|
||||||
# ...
|
|
||||||
}
|
|
||||||
|
|
||||||
# Wrong.
|
|
||||||
function do_something() {
|
|
||||||
# ...
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,99 +1,51 @@
|
|||||||
# Internal Variables
|
# Obsolete Syntax
|
||||||
|
|
||||||
**NOTE**: This list does not include every internal variable (*You can
|
## Shebang
|
||||||
help by adding a missing entry!*).
|
|
||||||
|
|
||||||
For a complete list, see:
|
Use `#!/usr/bin/env bash` instead of `#!/bin/bash`.
|
||||||
http://tldp.org/LDP/abs/html/internalvariables.html
|
|
||||||
|
|
||||||
## Get the location to the `bash` binary
|
- The former searches the user's `PATH` to find the `bash` binary.
|
||||||
|
- The latter assumes it is always installed to `/bin/` which can cause issues.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
"$BASH"
|
# Right:
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Wrong:
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the version of the current running `bash` process
|
## Command Substitution
|
||||||
|
|
||||||
|
Use `$()` instead of `` ` ` ``.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# As a string.
|
# Right.
|
||||||
"$BASH_VERSION"
|
var="$(command)"
|
||||||
|
|
||||||
# As an array.
|
# Wrong.
|
||||||
"${BASH_VERSINFO[@]}"
|
var=`command`
|
||||||
|
|
||||||
|
# $() can easily be nested whereas `` cannot.
|
||||||
|
var="$(command "$(command)")"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Open the user's preferred text editor
|
## Function Declaration
|
||||||
|
|
||||||
|
Don't use the `function` keyword, it reduces compatibility with older versions of `bash`.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
"$EDITOR" "$file"
|
# Right.
|
||||||
|
do_something() {
|
||||||
|
# ...
|
||||||
|
}
|
||||||
|
|
||||||
# NOTE: This variable may be empty, set a fallback value.
|
# Wrong.
|
||||||
"${EDITOR:-vi}" "$file"
|
function do_something() {
|
||||||
```
|
# ...
|
||||||
|
}
|
||||||
## Get the name of the current function
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Current function.
|
|
||||||
"${FUNCNAME[0]}"
|
|
||||||
|
|
||||||
# Parent function.
|
|
||||||
"${FUNCNAME[1]}"
|
|
||||||
|
|
||||||
# So on and so forth.
|
|
||||||
"${FUNCNAME[2]}"
|
|
||||||
"${FUNCNAME[3]}"
|
|
||||||
|
|
||||||
# All functions including parents.
|
|
||||||
"${FUNCNAME[@]}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the host-name of the system
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$HOSTNAME"
|
|
||||||
|
|
||||||
# NOTE: This variable may be empty.
|
|
||||||
# Optionally set a fallback to the hostname command.
|
|
||||||
"${HOSTNAME:-$(hostname)}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the architecture of the Operating System
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$HOSTTYPE"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the name of the Operating System / Kernel
|
|
||||||
|
|
||||||
This can be used to add conditional support for different Operating
|
|
||||||
Systems without needing to call `uname`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$OSTYPE"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the current working directory
|
|
||||||
|
|
||||||
This is an alternative to the `pwd` built-in.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$PWD"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the number of seconds the script has been running
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$SECONDS"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get a pseudorandom integer
|
|
||||||
|
|
||||||
Each time `$RANDOM` is used, a different integer between `0` and `32767` is returned. This variable should not be used for anything related to security (*this includes encryption keys etc*).
|
|
||||||
|
|
||||||
|
|
||||||
```shell
|
|
||||||
"$RANDOM"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,78 +1,99 @@
|
|||||||
# Information about the terminal
|
# Internal Variables
|
||||||
|
|
||||||
## Get the terminal size in lines and columns (*from a script*)
|
**NOTE**: This list does not include every internal variable (*You can
|
||||||
|
help by adding a missing entry!*).
|
||||||
|
|
||||||
This is handy when writing scripts in pure bash and `stty`/`tput` can’t be
|
For a complete list, see:
|
||||||
called.
|
http://tldp.org/LDP/abs/html/internalvariables.html
|
||||||
|
|
||||||
**Example Function:**
|
## Get the location to the `bash` binary
|
||||||
|
|
||||||
```sh
|
|
||||||
get_term_size() {
|
|
||||||
# Usage: get_term_size
|
|
||||||
|
|
||||||
# (:;:) is a micro sleep to ensure the variables are
|
|
||||||
# exported immediately.
|
|
||||||
shopt -s checkwinsize; (:;:)
|
|
||||||
printf '%s\n' "$LINES $COLUMNS"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Output: LINES COLUMNS
|
"$BASH"
|
||||||
$ get_term_size
|
|
||||||
15 55
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the terminal size in pixels
|
## Get the version of the current running `bash` process
|
||||||
|
|
||||||
**CAVEAT**: This does not work in some terminal emulators.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
get_window_size() {
|
|
||||||
# Usage: get_window_size
|
|
||||||
printf '%b' "${TMUX:+\\ePtmux;\\e}\\e[14t${TMUX:+\\e\\\\}"
|
|
||||||
IFS=';t' read -d t -t 0.05 -sra term_size
|
|
||||||
printf '%s\n' "${term_size[1]}x${term_size[2]}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Output: WIDTHxHEIGHT
|
# As a string.
|
||||||
$ get_window_size
|
"$BASH_VERSION"
|
||||||
1200x800
|
|
||||||
|
|
||||||
# Output (fail):
|
# As an array.
|
||||||
$ get_window_size
|
"${BASH_VERSINFO[@]}"
|
||||||
x
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the current cursor position
|
## Open the user's preferred text editor
|
||||||
|
|
||||||
This is useful when creating a TUI in pure bash.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
get_cursor_pos() {
|
|
||||||
# Usage: get_cursor_pos
|
|
||||||
IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
|
|
||||||
printf '%s\n' "$x $y"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Output: X Y
|
"$EDITOR" "$file"
|
||||||
$ get_cursor_pos
|
|
||||||
1 8
|
# NOTE: This variable may be empty, set a fallback value.
|
||||||
|
"${EDITOR:-vi}" "$file"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the name of the current function
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Current function.
|
||||||
|
"${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
# Parent function.
|
||||||
|
"${FUNCNAME[1]}"
|
||||||
|
|
||||||
|
# So on and so forth.
|
||||||
|
"${FUNCNAME[2]}"
|
||||||
|
"${FUNCNAME[3]}"
|
||||||
|
|
||||||
|
# All functions including parents.
|
||||||
|
"${FUNCNAME[@]}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the host-name of the system
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$HOSTNAME"
|
||||||
|
|
||||||
|
# NOTE: This variable may be empty.
|
||||||
|
# Optionally set a fallback to the hostname command.
|
||||||
|
"${HOSTNAME:-$(hostname)}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the architecture of the Operating System
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$HOSTTYPE"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the name of the Operating System / Kernel
|
||||||
|
|
||||||
|
This can be used to add conditional support for different Operating
|
||||||
|
Systems without needing to call `uname`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$OSTYPE"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the current working directory
|
||||||
|
|
||||||
|
This is an alternative to the `pwd` built-in.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$PWD"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the number of seconds the script has been running
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$SECONDS"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get a pseudorandom integer
|
||||||
|
|
||||||
|
Each time `$RANDOM` is used, a different integer between `0` and `32767` is returned. This variable should not be used for anything related to security (*this includes encryption keys etc*).
|
||||||
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
"$RANDOM"
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,150 +1,78 @@
|
|||||||
# Conversion
|
# Information about the terminal
|
||||||
|
|
||||||
## Convert a hex color to RGB
|
## Get the terminal size in lines and columns (*from a script*)
|
||||||
|
|
||||||
|
This is handy when writing scripts in pure bash and `stty`/`tput` can’t be
|
||||||
|
called.
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
hex_to_rgb() {
|
get_term_size() {
|
||||||
# Usage: hex_to_rgb "#FFFFFF"
|
# Usage: get_term_size
|
||||||
((r=16#${1:1:2}))
|
|
||||||
((g=16#${1:3:2}))
|
|
||||||
((b=16#${1:5:6}))
|
|
||||||
|
|
||||||
printf '%s\n' "$r $g $b"
|
# (:;:) is a micro sleep to ensure the variables are
|
||||||
|
# exported immediately.
|
||||||
|
shopt -s checkwinsize; (:;:)
|
||||||
|
printf '%s\n' "$LINES $COLUMNS"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ hex_to_rgb "#FFFFFF"
|
# Output: LINES COLUMNS
|
||||||
255 255 255
|
$ get_term_size
|
||||||
|
15 55
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Get the terminal size in pixels
|
||||||
|
|
||||||
## Convert an RGB color to hex
|
**CAVEAT**: This does not work in some terminal emulators.
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
rgb_to_hex() {
|
get_window_size() {
|
||||||
# Usage: rgb_to_hex "r" "g" "b"
|
# Usage: get_window_size
|
||||||
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
|
printf '%b' "${TMUX:+\\ePtmux;\\e}\\e[14t${TMUX:+\\e\\\\}"
|
||||||
|
IFS=';t' read -d t -t 0.05 -sra term_size
|
||||||
|
printf '%s\n' "${term_size[1]}x${term_size[2]}"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ rgb_to_hex "255" "255" "255"
|
# Output: WIDTHxHEIGHT
|
||||||
#FFFFFF
|
$ get_window_size
|
||||||
|
1200x800
|
||||||
|
|
||||||
|
# Output (fail):
|
||||||
|
$ get_window_size
|
||||||
|
x
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Get the current cursor position
|
||||||
|
|
||||||
# Code Golf
|
This is useful when creating a TUI in pure bash.
|
||||||
|
|
||||||
## Shorter `for` loop syntax
|
**Example Function:**
|
||||||
|
|
||||||
```shell
|
```sh
|
||||||
# Tiny C Style.
|
get_cursor_pos() {
|
||||||
for((;i++<10;)){ echo "$i";}
|
# Usage: get_cursor_pos
|
||||||
|
IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
|
||||||
# Undocumented method.
|
printf '%s\n' "$x $y"
|
||||||
for i in {1..10};{ echo "$i";}
|
|
||||||
|
|
||||||
# Expansion.
|
|
||||||
for i in {1..10}; do echo "$i"; done
|
|
||||||
|
|
||||||
# C Style.
|
|
||||||
for((i=0;i<=10;i++)); do echo "$i"; done
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shorter infinite loops
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Normal method
|
|
||||||
while :; do echo hi; done
|
|
||||||
|
|
||||||
# Shorter
|
|
||||||
for((;;)){ echo hi;}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shorter function declaration
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Normal method
|
|
||||||
f(){ echo hi;}
|
|
||||||
|
|
||||||
# Using a subshell
|
|
||||||
f()(echo hi)
|
|
||||||
|
|
||||||
# Using arithmetic
|
|
||||||
# You can use this to assign integer values.
|
|
||||||
# Example: f a=1
|
|
||||||
# f a++
|
|
||||||
f()(($1))
|
|
||||||
|
|
||||||
# Using tests, loops etc.
|
|
||||||
# NOTE: You can also use ‘while’, ‘until’, ‘case’, ‘(())’, ‘[[]]’.
|
|
||||||
f()if true; then echo "$1"; fi
|
|
||||||
f()for i in "$@"; do echo "$i"; done
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shorter `if` syntax
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# One line
|
|
||||||
# Note: The 3rd statement may run when the 1st is true
|
|
||||||
[[ "$var" == hello ]] && echo hi || echo bye
|
|
||||||
[[ "$var" == hello ]] && { echo hi; echo there; } || echo bye
|
|
||||||
|
|
||||||
# Multi line (no else, single statement)
|
|
||||||
# Note: The exit status may not be the same as with an if statement
|
|
||||||
[[ "$var" == hello ]] && \
|
|
||||||
echo hi
|
|
||||||
|
|
||||||
# Multi line (no else)
|
|
||||||
[[ "$var" == hello ]] && {
|
|
||||||
echo hi
|
|
||||||
# ...
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Simpler `case` statement to set variable
|
**Example Usage:**
|
||||||
|
|
||||||
We can use the `:` builtin to avoid repeating `variable=` in a case
|
|
||||||
statement. The `$_` variable stores the last argument of the last
|
|
||||||
successful command. `:` always succeeds so we can abuse it to store the
|
|
||||||
variable value.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Modified snippet from Neofetch.
|
# Output: X Y
|
||||||
case "$OSTYPE" in
|
$ get_cursor_pos
|
||||||
"darwin"*)
|
1 8
|
||||||
: "MacOS"
|
|
||||||
;;
|
|
||||||
|
|
||||||
"linux"*)
|
|
||||||
: "Linux"
|
|
||||||
;;
|
|
||||||
|
|
||||||
*"bsd"* | "dragonfly" | "bitrig")
|
|
||||||
: "BSD"
|
|
||||||
;;
|
|
||||||
|
|
||||||
"cygwin" | "msys" | "win32")
|
|
||||||
: "Windows"
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
printf '%s\n' "Unknown OS detected, aborting..." >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Finally, set the variable.
|
|
||||||
os="$_"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,192 +1,150 @@
|
|||||||
# Other
|
# Conversion
|
||||||
|
|
||||||
## Use `read` as an alternative to the `sleep` command
|
## Convert a hex color to RGB
|
||||||
|
|
||||||
I was surprised to find out `sleep` is an external command and isn't a
|
|
||||||
built-in.
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
read_sleep() {
|
hex_to_rgb() {
|
||||||
# Usage: sleep 1
|
# Usage: hex_to_rgb "#FFFFFF"
|
||||||
# sleep 0.2
|
((r=16#${1:1:2}))
|
||||||
read -rst "${1:-1}" -N 999
|
((g=16#${1:3:2}))
|
||||||
|
((b=16#${1:5:6}))
|
||||||
|
|
||||||
|
printf '%s\n' "$r $g $b"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
read_sleep 1
|
$ hex_to_rgb "#FFFFFF"
|
||||||
read_sleep 0.1
|
255 255 255
|
||||||
read_sleep 30
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Check if a program is in the user's PATH
|
|
||||||
|
|
||||||
```shell
|
## Convert an RGB color to hex
|
||||||
# There are 3 ways to do this and you can use either of
|
|
||||||
# these in the same way.
|
|
||||||
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 isn't installed).
|
|
||||||
if ! type -p convert &>/dev/null; then
|
|
||||||
printf '%s\n' "error: convert isn't installed, exiting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get the current date using `strftime`
|
|
||||||
|
|
||||||
Bash’s `printf` has a built-in method of getting the date which we can use
|
|
||||||
in place of the `date` command in a lot of cases.
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
date() {
|
rgb_to_hex() {
|
||||||
# Usage: date "format"
|
# Usage: rgb_to_hex "r" "g" "b"
|
||||||
# See: 'man strftime' for format.
|
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
|
||||||
printf "%($1)T\\n" "-1"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Using above function.
|
$ rgb_to_hex "255" "255" "255"
|
||||||
$ date "%a %d %b - %l:%M %p"
|
#FFFFFF
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Generate a UUID V4
|
|
||||||
|
|
||||||
**Example Function:**
|
# Code Golf
|
||||||
|
|
||||||
```sh
|
## Shorter `for` loop syntax
|
||||||
uuid() {
|
|
||||||
# Usage: uuid
|
|
||||||
C="89ab"
|
|
||||||
|
|
||||||
for ((N=0;N<16;++N)); do
|
```shell
|
||||||
B="$((RANDOM%256))"
|
# Tiny C Style.
|
||||||
|
for((;i++<10;)){ echo "$i";}
|
||||||
|
|
||||||
case "$N" in
|
# Undocumented method.
|
||||||
6) printf '4%x' "$((B%16))" ;;
|
for i in {1..10};{ echo "$i";}
|
||||||
8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;;
|
|
||||||
|
|
||||||
3|5|7|9)
|
# Expansion.
|
||||||
printf '%02x-' "$B"
|
for i in {1..10}; do echo "$i"; done
|
||||||
|
|
||||||
|
# C Style.
|
||||||
|
for((i=0;i<=10;i++)); do echo "$i"; done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shorter infinite loops
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Normal method
|
||||||
|
while :; do echo hi; done
|
||||||
|
|
||||||
|
# Shorter
|
||||||
|
for((;;)){ echo hi;}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shorter function declaration
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Normal method
|
||||||
|
f(){ echo hi;}
|
||||||
|
|
||||||
|
# Using a subshell
|
||||||
|
f()(echo hi)
|
||||||
|
|
||||||
|
# Using arithmetic
|
||||||
|
# You can use this to assign integer values.
|
||||||
|
# Example: f a=1
|
||||||
|
# f a++
|
||||||
|
f()(($1))
|
||||||
|
|
||||||
|
# Using tests, loops etc.
|
||||||
|
# NOTE: You can also use ‘while’, ‘until’, ‘case’, ‘(())’, ‘[[]]’.
|
||||||
|
f()if true; then echo "$1"; fi
|
||||||
|
f()for i in "$@"; do echo "$i"; done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shorter `if` syntax
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# One line
|
||||||
|
# Note: The 3rd statement may run when the 1st is true
|
||||||
|
[[ "$var" == hello ]] && echo hi || echo bye
|
||||||
|
[[ "$var" == hello ]] && { echo hi; echo there; } || echo bye
|
||||||
|
|
||||||
|
# Multi line (no else, single statement)
|
||||||
|
# Note: The exit status may not be the same as with an if statement
|
||||||
|
[[ "$var" == hello ]] && \
|
||||||
|
echo hi
|
||||||
|
|
||||||
|
# Multi line (no else)
|
||||||
|
[[ "$var" == hello ]] && {
|
||||||
|
echo hi
|
||||||
|
# ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Simpler `case` statement to set variable
|
||||||
|
|
||||||
|
We can use the `:` builtin to avoid repeating `variable=` in a case
|
||||||
|
statement. The `$_` variable stores the last argument of the last
|
||||||
|
successful command. `:` always succeeds so we can abuse it to store the
|
||||||
|
variable value.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Modified snippet from Neofetch.
|
||||||
|
case "$OSTYPE" in
|
||||||
|
"darwin"*)
|
||||||
|
: "MacOS"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"linux"*)
|
||||||
|
: "Linux"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*"bsd"* | "dragonfly" | "bitrig")
|
||||||
|
: "BSD"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"cygwin" | "msys" | "win32")
|
||||||
|
: "Windows"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
printf '%02x' "$B"
|
printf '%s\n' "Unknown OS detected, aborting..." >&2
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
|
||||||
|
|
||||||
printf '\n'
|
# Finally, set the variable.
|
||||||
}
|
os="$_"
|
||||||
```
|
|
||||||
|
|
||||||
**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 from your 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
193
manuscript/chapter17.txt
Normal file
193
manuscript/chapter17.txt
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Other
|
||||||
|
|
||||||
|
## Use `read` as an alternative to the `sleep` command
|
||||||
|
|
||||||
|
I was surprised to find out `sleep` is an external command and isn't a
|
||||||
|
built-in.
|
||||||
|
|
||||||
|
**CAVEAT:** Requires `bash` 4+
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
read_sleep() {
|
||||||
|
# Usage: sleep 1
|
||||||
|
# sleep 0.2
|
||||||
|
read -rst "${1:-1}" -N 999
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
read_sleep 1
|
||||||
|
read_sleep 0.1
|
||||||
|
read_sleep 30
|
||||||
|
```
|
||||||
|
|
||||||
|
## Check if a program is in the user's PATH
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# There are 3 ways to do this and you can use either of
|
||||||
|
# these in the same way.
|
||||||
|
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 isn't installed).
|
||||||
|
if ! type -p convert &>/dev/null; then
|
||||||
|
printf '%s\n' "error: convert isn't installed, exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the current date using `strftime`
|
||||||
|
|
||||||
|
Bash’s `printf` has a built-in method of getting the date which we can use
|
||||||
|
in place of the `date` command in a lot of cases.
|
||||||
|
|
||||||
|
**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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate a UUID V4
|
||||||
|
|
||||||
|
**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 from your 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
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
@@ -1,94 +1,129 @@
|
|||||||
# Loops
|
# Arrays
|
||||||
|
|
||||||
## Loop over a range of numbers
|
## Reverse an array
|
||||||
|
|
||||||
Don't use `seq`.
|
Enabling `extdebug` allows access to the `BASH_ARGV` array which stores
|
||||||
|
the current function’s arguments in reverse.
|
||||||
|
|
||||||
```shell
|
**Example Function:**
|
||||||
# Loop from 0-100 (no variable support).
|
|
||||||
for i in {0..100}; do
|
```sh
|
||||||
printf '%s\n' "$i"
|
reverse_array() {
|
||||||
done
|
# Usage: reverse_array "array"
|
||||||
|
shopt -s extdebug
|
||||||
|
f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
|
||||||
|
shopt -u extdebug
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loop over a variable range of numbers
|
**Example Usage:**
|
||||||
|
|
||||||
Don't use `seq`.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Loop from 0-VAR.
|
$ reverse_array 1 2 3 4 5
|
||||||
VAR=50
|
5
|
||||||
for ((i=0;i<=VAR;i++)); do
|
4
|
||||||
printf '%s\n' "$i"
|
3
|
||||||
done
|
2
|
||||||
|
1
|
||||||
|
|
||||||
|
$ arr=(red blue green)
|
||||||
|
$ reverse_array "${arr[@]}"
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
red
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loop over an array
|
## Remove duplicate array elements
|
||||||
|
|
||||||
```shell
|
Create a temporary associative array. When setting associative array
|
||||||
arr=(apples oranges tomatoes)
|
values and a duplicate assignment occurs, bash overwrites the key. This
|
||||||
|
allows us to effectively remove array duplicates.
|
||||||
|
|
||||||
# Just elements.
|
**CAVEAT:** Requires `bash` 4+
|
||||||
for element in "${arr[@]}"; do
|
|
||||||
printf '%s\n' "$element"
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
remove_array_dups() {
|
||||||
|
# Usage: remove_array_dups "array"
|
||||||
|
declare -A tmp_array
|
||||||
|
|
||||||
|
for i in "$@"; do
|
||||||
|
[[ "$i" ]] && IFS=" " tmp_array["${i:- }"]=1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
printf '%s\n' "${!tmp_array[@]}"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loop over an array with an index
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
arr=(apples oranges tomatoes)
|
$ remove_array_dups 1 1 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
|
||||||
# Elements and index.
|
$ arr=(red red green blue blue)
|
||||||
for i in "${!arr[@]}"; do
|
$ remove_array_dups "${arr[@]}"
|
||||||
printf '%s\n' "${arr[$i]}"
|
red
|
||||||
done
|
green
|
||||||
|
blue
|
||||||
# Alternative method.
|
|
||||||
for ((i=0;i<${#arr[@]};i++)); do
|
|
||||||
printf '%s\n' "${arr[$i]}"
|
|
||||||
done
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loop over the contents of a file
|
## Random array element
|
||||||
|
|
||||||
```shell
|
**Example Function:**
|
||||||
while read -r line; do
|
|
||||||
printf '%s\n' "$line"
|
```sh
|
||||||
done < "file"
|
random_array_element() {
|
||||||
|
# Usage: random_array_element "array"
|
||||||
|
local arr=("$@")
|
||||||
|
printf '%s\n' "${arr[RANDOM % $#]}"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loop over files and directories
|
**Example Usage:**
|
||||||
|
|
||||||
Don’t use `ls`.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Greedy example.
|
$ array=(red green blue yellow brown)
|
||||||
for file in *; do
|
$ random_array_element "${array[@]}"
|
||||||
printf '%s\n' "$file"
|
yellow
|
||||||
done
|
|
||||||
|
|
||||||
# PNG files in dir.
|
# You can also just pass multiple arguments.
|
||||||
for file in ~/Pictures/*.png; do
|
$ random_array_element 1 2 3 4 5 6 7
|
||||||
printf '%s\n' "$file"
|
3
|
||||||
done
|
```
|
||||||
|
|
||||||
# Iterate over directories.
|
## Cycle through an array
|
||||||
for dir in ~/Downloads/*/; do
|
|
||||||
printf '%s\n' "$dir"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Brace Expansion.
|
Each time the `printf` is called, the next array element is printed. When
|
||||||
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
|
the print hits the last array element it starts from the first element
|
||||||
printf '%s\n' "$file"
|
again.
|
||||||
done
|
|
||||||
|
|
||||||
# Iterate recursively.
|
```sh
|
||||||
shopt -s globstar
|
arr=(a b c d)
|
||||||
for file in ~/Pictures/**/*; do
|
|
||||||
printf '%s\n' "$file"
|
cycle() {
|
||||||
done
|
printf '%s ' "${arr[${i:=0}]}"
|
||||||
shopt -u globstar
|
((i=i>=${#arr[@]}-1?0:++i))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Toggle between two values
|
||||||
|
|
||||||
|
This works the same as above, this is just a different use case.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
arr=(true false)
|
||||||
|
|
||||||
|
cycle() {
|
||||||
|
printf '%s ' "${arr[${i:=0}]}"
|
||||||
|
((i=i>=${#arr[@]}-1?0:++i))
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,188 +1,94 @@
|
|||||||
# File handling
|
# Loops
|
||||||
|
|
||||||
**CAVEAT:** `bash` doesn't handle binary data properly in versions `< 4.4`.
|
## Loop over a range of numbers
|
||||||
|
|
||||||
## Read a file to a string
|
Don't use `seq`.
|
||||||
|
|
||||||
Alternative to the `cat` command.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
file_data="$(<"file")"
|
# Loop from 0-100 (no variable support).
|
||||||
|
for i in {0..100}; do
|
||||||
|
printf '%s\n' "$i"
|
||||||
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
## Read a file to an array (*by line*)
|
## Loop over a variable range of numbers
|
||||||
|
|
||||||
Alternative to the `cat` command.
|
Don't use `seq`.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Bash <4
|
# Loop from 0-VAR.
|
||||||
IFS=$'\n' read -d "" -ra file_data < "file"
|
VAR=50
|
||||||
|
for ((i=0;i<=VAR;i++)); do
|
||||||
# Bash 4+
|
printf '%s\n' "$i"
|
||||||
mapfile -t file_data < "file"
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the first N lines of a file
|
## Loop over an array
|
||||||
|
|
||||||
Alternative to the `head` command.
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
head() {
|
|
||||||
# Usage: head "n" "file"
|
|
||||||
mapfile -tn "$1" line < "$2"
|
|
||||||
printf '%s\n' "${line[@]}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ head 2 ~/.bashrc
|
arr=(apples oranges tomatoes)
|
||||||
# Prompt
|
|
||||||
PS1='➜ '
|
|
||||||
|
|
||||||
$ head 1 ~/.bashrc
|
# Just elements.
|
||||||
# Prompt
|
for element in "${arr[@]}"; do
|
||||||
|
printf '%s\n' "$element"
|
||||||
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the last N lines of a file
|
## Loop over an array with an index
|
||||||
|
|
||||||
Alternative to the `tail` command.
|
|
||||||
|
|
||||||
**CAVEAT:** Requires `bash` 4+
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
tail() {
|
|
||||||
# Usage: tail "n" "file"
|
|
||||||
mapfile -tn 0 line < "$2"
|
|
||||||
printf '%s\n' "${line[@]: -$1}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ tail 2 ~/.bashrc
|
arr=(apples oranges tomatoes)
|
||||||
# Enable tmux.
|
|
||||||
# [[ -z "$TMUX" ]] && exec tmux
|
|
||||||
|
|
||||||
$ tail 1 ~/.bashrc
|
# Elements and index.
|
||||||
# [[ -z "$TMUX" ]] && exec tmux
|
for i in "${!arr[@]}"; do
|
||||||
|
printf '%s\n' "${arr[$i]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Alternative method.
|
||||||
|
for ((i=0;i<${#arr[@]};i++)); do
|
||||||
|
printf '%s\n' "${arr[$i]}"
|
||||||
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the number of lines in a file
|
## Loop over the contents of a file
|
||||||
|
|
||||||
Alternative to `wc -l`.
|
|
||||||
|
|
||||||
**Example Function (bash 4):**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lines() {
|
|
||||||
# Usage: lines "file"
|
|
||||||
mapfile -tn 0 lines < "$1"
|
|
||||||
printf '%s\n' "${#lines[@]}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Function (bash 3):**
|
|
||||||
|
|
||||||
This method uses less memory than the `mapfile` method and it's more
|
|
||||||
compatible but it's slower for bigger files.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lines_loop() {
|
|
||||||
# Usage: lines_loop "file"
|
|
||||||
count=0
|
|
||||||
while IFS= read -r _; do
|
|
||||||
((count++))
|
|
||||||
done < "$1"
|
|
||||||
printf '%s\n' "$count"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ lines ~/.bashrc
|
while read -r line; do
|
||||||
48
|
|
||||||
|
|
||||||
$ lines_loop ~/.bashrc
|
|
||||||
48
|
|
||||||
```
|
|
||||||
|
|
||||||
## Count files or directories in directory
|
|
||||||
|
|
||||||
This works by passing the output of the glob as function arguments. We
|
|
||||||
then count the arguments and print the number.
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
count() {
|
|
||||||
# Usage: count /path/to/dir/*
|
|
||||||
# count /path/to/dir/*/
|
|
||||||
printf '%s\n' "$#"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example Usage:**
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Count all files in dir.
|
|
||||||
$ count ~/Downloads/*
|
|
||||||
232
|
|
||||||
|
|
||||||
# Count all dirs in dir.
|
|
||||||
$ count ~/Downloads/*/
|
|
||||||
45
|
|
||||||
|
|
||||||
# Count all jpg files in dir.
|
|
||||||
$ count ~/Pictures/*.jpg
|
|
||||||
64
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create an empty file
|
|
||||||
|
|
||||||
Alternative to `touch`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Shortest.
|
|
||||||
:> file
|
|
||||||
|
|
||||||
# Longer alternatives:
|
|
||||||
echo -n > file
|
|
||||||
printf '' > file
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extract lines between two markers
|
|
||||||
|
|
||||||
**Example Function:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
extract() {
|
|
||||||
# Usage: extract file "opening marker" "closing marker"
|
|
||||||
while IFS=$'\n' read -r line; do
|
|
||||||
[[ "$extract" && "$line" != "$3" ]] && \
|
|
||||||
printf '%s\n' "$line"
|
printf '%s\n' "$line"
|
||||||
|
done < "file"
|
||||||
[[ "$line" == "$2" ]] && extract=1
|
|
||||||
[[ "$line" == "$3" ]] && extract=
|
|
||||||
done < "$1"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
## Loop over files and directories
|
||||||
|
|
||||||
|
Don’t use `ls`.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Extract code blocks from MarkDown file.
|
# Greedy example.
|
||||||
$ extract ~/projects/pure-bash/README.md '```sh' '```'
|
for file in *; do
|
||||||
# Output here...
|
printf '%s\n' "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# PNG files in dir.
|
||||||
|
for file in ~/Pictures/*.png; do
|
||||||
|
printf '%s\n' "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Iterate over directories.
|
||||||
|
for dir in ~/Downloads/*/; do
|
||||||
|
printf '%s\n' "$dir"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Brace Expansion.
|
||||||
|
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
|
||||||
|
printf '%s\n' "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Iterate recursively.
|
||||||
|
shopt -s globstar
|
||||||
|
for file in ~/Pictures/**/*; do
|
||||||
|
printf '%s\n' "$file"
|
||||||
|
done
|
||||||
|
shopt -u globstar
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,50 +1,188 @@
|
|||||||
# File Paths
|
# File handling
|
||||||
|
|
||||||
## Get the directory name of a file path
|
**CAVEAT:** `bash` doesn't handle binary data properly in versions `< 4.4`.
|
||||||
|
|
||||||
Alternative to the `dirname` command.
|
## Read a file to a string
|
||||||
|
|
||||||
|
Alternative to the `cat` command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
file_data="$(<"file")"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read a file to an array (*by line*)
|
||||||
|
|
||||||
|
Alternative to the `cat` command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Bash <4
|
||||||
|
IFS=$'\n' read -d "" -ra file_data < "file"
|
||||||
|
|
||||||
|
# Bash 4+
|
||||||
|
mapfile -t file_data < "file"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the first N lines of a file
|
||||||
|
|
||||||
|
Alternative to the `head` command.
|
||||||
|
|
||||||
|
**CAVEAT:** Requires `bash` 4+
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
dirname() {
|
head() {
|
||||||
# Usage: dirname "path"
|
# Usage: head "n" "file"
|
||||||
printf '%s\n' "${1%/*}/"
|
mapfile -tn "$1" line < "$2"
|
||||||
|
printf '%s\n' "${line[@]}"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ dirname ~/Pictures/Wallpapers/1.jpg
|
$ head 2 ~/.bashrc
|
||||||
/home/black/Pictures/Wallpapers/
|
# Prompt
|
||||||
|
PS1='➜ '
|
||||||
|
|
||||||
$ dirname ~/Pictures/Downloads/
|
$ head 1 ~/.bashrc
|
||||||
/home/black/Pictures/
|
# Prompt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the base-name of a file path
|
## Get the last N lines of a file
|
||||||
|
|
||||||
Alternative to the `basename` command.
|
Alternative to the `tail` command.
|
||||||
|
|
||||||
|
**CAVEAT:** Requires `bash` 4+
|
||||||
|
|
||||||
**Example Function:**
|
**Example Function:**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
basename() {
|
tail() {
|
||||||
# Usage: basename "path"
|
# Usage: tail "n" "file"
|
||||||
: "${1%/}"
|
mapfile -tn 0 line < "$2"
|
||||||
printf '%s\n' "${_##*/}"
|
printf '%s\n' "${line[@]: -$1}"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ basename ~/Pictures/Wallpapers/1.jpg
|
$ tail 2 ~/.bashrc
|
||||||
1.jpg
|
# Enable tmux.
|
||||||
|
# [[ -z "$TMUX" ]] && exec tmux
|
||||||
|
|
||||||
$ basename ~/Pictures/Downloads/
|
$ tail 1 ~/.bashrc
|
||||||
Downloads
|
# [[ -z "$TMUX" ]] && exec tmux
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get the number of lines in a file
|
||||||
|
|
||||||
|
Alternative to `wc -l`.
|
||||||
|
|
||||||
|
**Example Function (bash 4):**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lines() {
|
||||||
|
# Usage: lines "file"
|
||||||
|
mapfile -tn 0 lines < "$1"
|
||||||
|
printf '%s\n' "${#lines[@]}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Function (bash 3):**
|
||||||
|
|
||||||
|
This method uses less memory than the `mapfile` method and it's more
|
||||||
|
compatible but it's slower for bigger files.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lines_loop() {
|
||||||
|
# Usage: lines_loop "file"
|
||||||
|
count=0
|
||||||
|
while IFS= read -r _; do
|
||||||
|
((count++))
|
||||||
|
done < "$1"
|
||||||
|
printf '%s\n' "$count"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ lines ~/.bashrc
|
||||||
|
48
|
||||||
|
|
||||||
|
$ lines_loop ~/.bashrc
|
||||||
|
48
|
||||||
|
```
|
||||||
|
|
||||||
|
## Count files or directories in directory
|
||||||
|
|
||||||
|
This works by passing the output of the glob as function arguments. We
|
||||||
|
then count the arguments and print the number.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
count() {
|
||||||
|
# Usage: count /path/to/dir/*
|
||||||
|
# count /path/to/dir/*/
|
||||||
|
printf '%s\n' "$#"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Count all files in dir.
|
||||||
|
$ count ~/Downloads/*
|
||||||
|
232
|
||||||
|
|
||||||
|
# Count all dirs in dir.
|
||||||
|
$ count ~/Downloads/*/
|
||||||
|
45
|
||||||
|
|
||||||
|
# Count all jpg files in dir.
|
||||||
|
$ count ~/Pictures/*.jpg
|
||||||
|
64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create an empty file
|
||||||
|
|
||||||
|
Alternative to `touch`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Shortest.
|
||||||
|
:> file
|
||||||
|
|
||||||
|
# Longer alternatives:
|
||||||
|
echo -n > file
|
||||||
|
printf '' > file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extract lines between two markers
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
extract() {
|
||||||
|
# Usage: extract file "opening marker" "closing marker"
|
||||||
|
while IFS=$'\n' read -r line; do
|
||||||
|
[[ "$extract" && "$line" != "$3" ]] && \
|
||||||
|
printf '%s\n' "$line"
|
||||||
|
|
||||||
|
[[ "$line" == "$2" ]] && extract=1
|
||||||
|
[[ "$line" == "$3" ]] && extract=
|
||||||
|
done < "$1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Extract code blocks from MarkDown file.
|
||||||
|
$ extract ~/projects/pure-bash/README.md '```sh' '```'
|
||||||
|
# Output here...
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,16 +1,50 @@
|
|||||||
# Variables
|
# File Paths
|
||||||
|
|
||||||
## Assign and access a variable using a variable
|
## Get the directory name of a file path
|
||||||
|
|
||||||
|
Alternative to the `dirname` command.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dirname() {
|
||||||
|
# Usage: dirname "path"
|
||||||
|
printf '%s\n' "${1%/*}/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
hello_world="test"
|
$ dirname ~/Pictures/Wallpapers/1.jpg
|
||||||
|
/home/black/Pictures/Wallpapers/
|
||||||
|
|
||||||
# Create the variable name.
|
$ dirname ~/Pictures/Downloads/
|
||||||
var1="world"
|
/home/black/Pictures/
|
||||||
var2="hello_${var1}"
|
```
|
||||||
|
|
||||||
# Print the value of the variable name stored in 'hello_$var1'.
|
## Get the base-name of a file path
|
||||||
printf '%s\n' "${!var2}"
|
|
||||||
|
Alternative to the `basename` command.
|
||||||
|
|
||||||
|
**Example Function:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
basename() {
|
||||||
|
# Usage: basename "path"
|
||||||
|
: "${1%/}"
|
||||||
|
printf '%s\n' "${_##*/}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ basename ~/Pictures/Wallpapers/1.jpg
|
||||||
|
1.jpg
|
||||||
|
|
||||||
|
$ basename ~/Pictures/Downloads/
|
||||||
|
Downloads
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,57 +1,17 @@
|
|||||||
# Escape Sequences
|
# Variables
|
||||||
|
|
||||||
Contrary to popular belief, there's no issue in using raw escape sequences. Using `tput` just abstracts the same ANSI escape sequences. What's worse is that `tput` isn't actually portable, there are a number of different `tput` variants on different Operating Systems each with different commands (*try and run `tput setaf 3` on a FreeBSD system*). The easiest solution ends up being raw ANSI sequences.
|
## Assign and access a variable using a variable
|
||||||
|
|
||||||
## Text Colors
|
```shell
|
||||||
|
hello_world="test"
|
||||||
|
|
||||||
**NOTE:** Sequences requiring RGB values only work in True-Color Terminal Emulators.
|
# Create the variable name.
|
||||||
|
var1="world"
|
||||||
| Sequence | What does it do? | Value |
|
var2="hello_${var1}"
|
||||||
| -------- | ---------------- | ----- |
|
|
||||||
| `\e[38;5;<NUM>m` | Set text foreground color. | `0-255`
|
|
||||||
| `\e[48;5;<NUM>m` | Set text background color. | `0-255`
|
|
||||||
| `\e[38;2;<R>;<G>;<B>m` | Set text foreground color to RGB color. | `R`, `G`, `B`
|
|
||||||
| `\e[48;2;<R>;<G>;<B>m` | Set text background color to RGB color. | `R`, `G`, `B`
|
|
||||||
|
|
||||||
## Text Attributes
|
|
||||||
|
|
||||||
| Sequence | What does it do? |
|
|
||||||
| -------- | ---------------- |
|
|
||||||
| `\e[m` | Reset text formatting and colors.
|
|
||||||
| `\e[1m` | Bold text. |
|
|
||||||
| `\e[2m` | Faint text. |
|
|
||||||
| `\e[3m` | Italic text. |
|
|
||||||
| `\e[4m` | Underline text. |
|
|
||||||
| `\e[5m` | Slow blink. |
|
|
||||||
| `\e[7m` | Swap foreground and background colors. |
|
|
||||||
|
|
||||||
|
|
||||||
## Cursor Movement
|
|
||||||
|
|
||||||
| Sequence | What does it do? | Value |
|
|
||||||
| -------- | ---------------- | ----- |
|
|
||||||
| `\e[<LINE>;<COLUMN>H` | Move cursor to absolute position. | `line`, `column`
|
|
||||||
| `\e[H` | Move cursor to home position (`0,0`). |
|
|
||||||
| `\e[<NUM>A` | Move cursor up N lines. | `num`
|
|
||||||
| `\e[<NUM>B` | Move cursor down N lines. | `num`
|
|
||||||
| `\e[<NUM>C` | Move cursor right N columns. | `num`
|
|
||||||
| `\e[<NUM>D` | Move cursor left N columns. | `num`
|
|
||||||
| `\e[s` | Save cursor position. |
|
|
||||||
| `\e[u` | Restore cursor position. |
|
|
||||||
|
|
||||||
|
|
||||||
## Erasing Text
|
|
||||||
|
|
||||||
| Sequence | What does it do? |
|
|
||||||
| -------- | ---------------- |
|
|
||||||
| `\e[K` | Erase from cursor position to end of line.
|
|
||||||
| `\e[1K` | Erase from cursor position to start of line.
|
|
||||||
| `\e[2K` | Erase the entire current line.
|
|
||||||
| `\e[J` | Erase from the current line to the bottom of the screen.
|
|
||||||
| `\e[1J` | Erase from the current line to the top of the screen.
|
|
||||||
| `\e[2J` | Clear the screen.
|
|
||||||
| `\e[2J\e[H` | Clear the screen and move cursor to `0,0`.
|
|
||||||
|
|
||||||
|
# Print the value of the variable name stored in 'hello_$var1'.
|
||||||
|
printf '%s\n' "${!var2}"
|
||||||
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +1,56 @@
|
|||||||
# Parameter Expansion
|
# Escape Sequences
|
||||||
|
|
||||||
## Indirection
|
Contrary to popular belief, there's no issue in using raw escape sequences. Using `tput` just abstracts the same ANSI escape sequences. What's worse is that `tput` isn't actually portable, there are a number of different `tput` variants on different Operating Systems each with different commands (*try and run `tput setaf 3` on a FreeBSD system*). The easiest solution ends up being raw ANSI sequences.
|
||||||
|
|
||||||
| Parameter | What does it do? |
|
## Text Colors
|
||||||
| --------- | ---------------- |
|
|
||||||
| `${!VAR}` | Access a variable based on the value of `VAR`. See: [link](#assign-and-access-a-variable-using-a-variable)
|
**NOTE:** Sequences requiring RGB values only work in True-Color Terminal Emulators.
|
||||||
| `${!VAR*}` | Expand to `IFS` separated list of variable names starting with `VAR`. |
|
|
||||||
| `${!VAR@}` | Expand to `IFS` separated list of variable names starting with `VAR`. |
|
| Sequence | What does it do? | Value |
|
||||||
|
| -------- | ---------------- | ----- |
|
||||||
|
| `\e[38;5;<NUM>m` | Set text foreground color. | `0-255`
|
||||||
|
| `\e[48;5;<NUM>m` | Set text background color. | `0-255`
|
||||||
|
| `\e[38;2;<R>;<G>;<B>m` | Set text foreground color to RGB color. | `R`, `G`, `B`
|
||||||
|
| `\e[48;2;<R>;<G>;<B>m` | Set text background color to RGB color. | `R`, `G`, `B`
|
||||||
|
|
||||||
|
## Text Attributes
|
||||||
|
|
||||||
|
| Sequence | What does it do? |
|
||||||
|
| -------- | ---------------- |
|
||||||
|
| `\e[m` | Reset text formatting and colors.
|
||||||
|
| `\e[1m` | Bold text. |
|
||||||
|
| `\e[2m` | Faint text. |
|
||||||
|
| `\e[3m` | Italic text. |
|
||||||
|
| `\e[4m` | Underline text. |
|
||||||
|
| `\e[5m` | Slow blink. |
|
||||||
|
| `\e[7m` | Swap foreground and background colors. |
|
||||||
|
|
||||||
|
|
||||||
## Replacement
|
## Cursor Movement
|
||||||
|
|
||||||
| Parameter | What does it do? |
|
| Sequence | What does it do? | Value |
|
||||||
| --------- | ---------------- |
|
| -------- | ---------------- | ----- |
|
||||||
| `${VAR#PATTERN}` | Remove shortest match of pattern from start of string. |
|
| `\e[<LINE>;<COLUMN>H` | Move cursor to absolute position. | `line`, `column`
|
||||||
| `${VAR##PATTERN}` | Remove longest match of pattern from start of string. |
|
| `\e[H` | Move cursor to home position (`0,0`). |
|
||||||
| `${VAR%PATTERN}` | Remove shortest match of pattern from end of string. |
|
| `\e[<NUM>A` | Move cursor up N lines. | `num`
|
||||||
| `${VAR%%PATTERN}` | Remove longest match of pattern from end of string. |
|
| `\e[<NUM>B` | Move cursor down N lines. | `num`
|
||||||
| `${VAR/PATTERN/REPLACE}` | Replace first match with string.
|
| `\e[<NUM>C` | Move cursor right N columns. | `num`
|
||||||
| `${VAR//PATTERN/REPLACE}` | Replace all matches with string.
|
| `\e[<NUM>D` | Move cursor left N columns. | `num`
|
||||||
| `${VAR/PATTERN}` | Remove first match.
|
| `\e[s` | Save cursor position. |
|
||||||
| `${VAR//PATTERN}` | Remove all matches.
|
| `\e[u` | Restore cursor position. |
|
||||||
|
|
||||||
## Length
|
|
||||||
|
|
||||||
| Parameter | What does it do? |
|
|
||||||
| --------- | ---------------- |
|
|
||||||
| `${#VAR}` | Length of var in characters.
|
|
||||||
| `${#ARR[@]}` | Length of array in elements.
|
|
||||||
|
|
||||||
## Expansion
|
|
||||||
|
|
||||||
| Parameter | What does it do? |
|
|
||||||
| --------- | ---------------- |
|
|
||||||
| `${VAR:OFFSET}` | Remove first `N` chars from variable.
|
|
||||||
| `${VAR:OFFSET:LENGTH}` | Get substring from `N` character to `N` character. <br> (`${VAR:10:10}`: Get sub-string from char `10` to char `20`)
|
|
||||||
| `${VAR:: OFFSET}` | Get first `N` chars from variable.
|
|
||||||
| `${VAR:: -OFFSET}` | Remove last `N` chars from variable.
|
|
||||||
| `${VAR: -OFFSET}` | Get last `N` chars from variable.
|
|
||||||
| `${VAR:OFFSET:-OFFSET}` | Cut first `N` chars and last `N` chars. | `bash 4.2+` |
|
|
||||||
|
|
||||||
## Case Modification
|
|
||||||
|
|
||||||
| Parameter | What does it do? | CAVEAT |
|
|
||||||
| --------- | ---------------- | ------ |
|
|
||||||
| `${VAR^}` | Uppercase first character. | `bash 4+` |
|
|
||||||
| `${VAR^^}` | Uppercase all characters. | `bash 4+` |
|
|
||||||
| `${VAR,}` | Lowercase first character. | `bash 4+` |
|
|
||||||
| `${VAR,,}` | Lowercase all characters. | `bash 4+` |
|
|
||||||
|
|
||||||
|
|
||||||
## Default Value
|
## Erasing Text
|
||||||
|
|
||||||
| Parameter | What does it do? |
|
| Sequence | What does it do? |
|
||||||
| --------- | ---------------- |
|
| -------- | ---------------- |
|
||||||
| `${VAR:-STRING}` | If `VAR` is empty or unset, use `STRING` as it's value.
|
| `\e[K` | Erase from cursor position to end of line.
|
||||||
| `${VAR-STRING}` | If `VAR` is unset, use `STRING` as it's value.
|
| `\e[1K` | Erase from cursor position to start of line.
|
||||||
| `${VAR:=STRING}` | If `VAR` is empty or unset, set the value of `VAR` to `STRING`.
|
| `\e[2K` | Erase the entire current line.
|
||||||
| `${VAR=STRING}` | If `VAR` is unset, set the value of `VAR` to `STRING`.
|
| `\e[J` | Erase from the current line to the bottom of the screen.
|
||||||
| `${VAR:+STRING}` | If `VAR` isn't empty, use `STRING` as it's value.
|
| `\e[1J` | Erase from the current line to the top of the screen.
|
||||||
| `${VAR+STRING}` | If `VAR` is set, use `STRING` as it's value.
|
| `\e[2J` | Clear the screen.
|
||||||
| `${VAR:?STRING}` | Display an error if empty or unset.
|
| `\e[2J\e[H` | Clear the screen and move cursor to `0,0`.
|
||||||
| `${VAR?STRING}` | Display an error if unset.
|
|
||||||
|
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
@@ -1,42 +1,68 @@
|
|||||||
# Brace Expansion
|
# Parameter Expansion
|
||||||
|
|
||||||
## Ranges
|
## Indirection
|
||||||
|
|
||||||
```shell
|
| Parameter | What does it do? |
|
||||||
# Syntax: {<START>..<END>}
|
| --------- | ---------------- |
|
||||||
|
| `${!VAR}` | Access a variable based on the value of `VAR`. See: [link](#assign-and-access-a-variable-using-a-variable)
|
||||||
|
| `${!VAR*}` | Expand to `IFS` separated list of variable names starting with `VAR`. |
|
||||||
|
| `${!VAR@}` | Expand to `IFS` separated list of variable names starting with `VAR`. |
|
||||||
|
|
||||||
# Print numbers 1-100.
|
|
||||||
echo {1..100}
|
|
||||||
|
|
||||||
# Print range of floats.
|
## Replacement
|
||||||
echo 1.{1..9}
|
|
||||||
|
|
||||||
# Print chars a-z.
|
| Parameter | What does it do? |
|
||||||
echo {a..z}
|
| --------- | ---------------- |
|
||||||
echo {A..Z}
|
| `${VAR#PATTERN}` | Remove shortest match of pattern from start of string. |
|
||||||
|
| `${VAR##PATTERN}` | Remove longest match of pattern from start of string. |
|
||||||
|
| `${VAR%PATTERN}` | Remove shortest match of pattern from end of string. |
|
||||||
|
| `${VAR%%PATTERN}` | Remove longest match of pattern from end of string. |
|
||||||
|
| `${VAR/PATTERN/REPLACE}` | Replace first match with string.
|
||||||
|
| `${VAR//PATTERN/REPLACE}` | Replace all matches with string.
|
||||||
|
| `${VAR/PATTERN}` | Remove first match.
|
||||||
|
| `${VAR//PATTERN}` | Remove all matches.
|
||||||
|
|
||||||
# Nesting.
|
## Length
|
||||||
echo {A..Z}{0..9}
|
|
||||||
|
|
||||||
# Print zero-padded numbers.
|
| Parameter | What does it do? |
|
||||||
# CAVEAT: bash 4+
|
| --------- | ---------------- |
|
||||||
echo {01..100}
|
| `${#VAR}` | Length of var in characters.
|
||||||
|
| `${#ARR[@]}` | Length of array in elements.
|
||||||
|
|
||||||
# Change increment amount.
|
## Expansion
|
||||||
# Syntax: {<START>..<END>..<INCREMENT>}
|
|
||||||
# CAVEAT: bash 4+
|
|
||||||
echo {1..10..2} # Increment by 2.
|
|
||||||
```
|
|
||||||
|
|
||||||
## String Lists
|
| Parameter | What does it do? |
|
||||||
|
| --------- | ---------------- |
|
||||||
|
| `${VAR:OFFSET}` | Remove first `N` chars from variable.
|
||||||
|
| `${VAR:OFFSET:LENGTH}` | Get substring from `N` character to `N` character. <br> (`${VAR:10:10}`: Get sub-string from char `10` to char `20`)
|
||||||
|
| `${VAR:: OFFSET}` | Get first `N` chars from variable.
|
||||||
|
| `${VAR:: -OFFSET}` | Remove last `N` chars from variable.
|
||||||
|
| `${VAR: -OFFSET}` | Get last `N` chars from variable.
|
||||||
|
| `${VAR:OFFSET:-OFFSET}` | Cut first `N` chars and last `N` chars. | `bash 4.2+` |
|
||||||
|
|
||||||
```shell
|
## Case Modification
|
||||||
echo {apples,oranges,pears,grapes}
|
|
||||||
|
| Parameter | What does it do? | CAVEAT |
|
||||||
|
| --------- | ---------------- | ------ |
|
||||||
|
| `${VAR^}` | Uppercase first character. | `bash 4+` |
|
||||||
|
| `${VAR^^}` | Uppercase all characters. | `bash 4+` |
|
||||||
|
| `${VAR,}` | Lowercase first character. | `bash 4+` |
|
||||||
|
| `${VAR,,}` | Lowercase all characters. | `bash 4+` |
|
||||||
|
|
||||||
|
|
||||||
|
## Default Value
|
||||||
|
|
||||||
|
| Parameter | What does it do? |
|
||||||
|
| --------- | ---------------- |
|
||||||
|
| `${VAR:-STRING}` | If `VAR` is empty or unset, use `STRING` as it's value.
|
||||||
|
| `${VAR-STRING}` | If `VAR` is unset, use `STRING` as it's value.
|
||||||
|
| `${VAR:=STRING}` | If `VAR` is empty or unset, set the value of `VAR` to `STRING`.
|
||||||
|
| `${VAR=STRING}` | If `VAR` is unset, set the value of `VAR` to `STRING`.
|
||||||
|
| `${VAR:+STRING}` | If `VAR` isn't empty, use `STRING` as it's value.
|
||||||
|
| `${VAR+STRING}` | If `VAR` is set, use `STRING` as it's value.
|
||||||
|
| `${VAR:?STRING}` | Display an error if empty or unset.
|
||||||
|
| `${VAR?STRING}` | Display an error if unset.
|
||||||
|
|
||||||
# Example Usage:
|
|
||||||
# Remove dirs Movies, Music and ISOS from ~/Downloads/.
|
|
||||||
rm -rf ~/Downloads/{Movies,Music,ISOS}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,41 @@
|
|||||||
# Arithmetic
|
# Brace Expansion
|
||||||
|
|
||||||
## Simpler syntax to set variables
|
## Ranges
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Simple math
|
# Syntax: {<START>..<END>}
|
||||||
((var=1+2))
|
|
||||||
|
|
||||||
# Decrement/Increment variable
|
# Print numbers 1-100.
|
||||||
((var++))
|
echo {1..100}
|
||||||
((var--))
|
|
||||||
((var+=1))
|
|
||||||
((var-=1))
|
|
||||||
|
|
||||||
# Using variables
|
# Print range of floats.
|
||||||
((var=var2*arr[2]))
|
echo 1.{1..9}
|
||||||
|
|
||||||
|
# Print chars a-z.
|
||||||
|
echo {a..z}
|
||||||
|
echo {A..Z}
|
||||||
|
|
||||||
|
# Nesting.
|
||||||
|
echo {A..Z}{0..9}
|
||||||
|
|
||||||
|
# Print zero-padded numbers.
|
||||||
|
# CAVEAT: bash 4+
|
||||||
|
echo {01..100}
|
||||||
|
|
||||||
|
# Change increment amount.
|
||||||
|
# Syntax: {<START>..<END>..<INCREMENT>}
|
||||||
|
# CAVEAT: bash 4+
|
||||||
|
echo {1..10..2} # Increment by 2.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ternary tests
|
## String Lists
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Set the value of var to var2 if var2 is greater than var.
|
echo {apples,oranges,pears,grapes}
|
||||||
# var: variable to set.
|
|
||||||
# var2>var: Condition to test.
|
# Example Usage:
|
||||||
# ?var2: If the test succeeds.
|
# Remove dirs Movies, Music and ISOS from ~/Downloads/.
|
||||||
# :var: If the test fails.
|
rm -rf ~/Downloads/{Movies,Music,ISOS}
|
||||||
((var=var2>var?var2:var))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- CHAPTER END -->
|
<!-- CHAPTER END -->
|
||||||
|
|||||||
Reference in New Issue
Block a user