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>
|
||||
|
||||
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
|
||||
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
|
||||
@@ -45,6 +45,7 @@ scripts and not full blown utilities.
|
||||
|
||||
<!-- vim-markdown-toc GFM -->
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Strings](#strings)
|
||||
* [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)
|
||||
@@ -156,6 +157,17 @@ scripts and not full blown utilities.
|
||||
|
||||
<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 -->
|
||||
# Strings
|
||||
|
||||
|
||||
@@ -15,3 +15,4 @@ chapter13.txt
|
||||
chapter14.txt
|
||||
chapter15.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
|
||||
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.
|
||||
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.
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```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
|
||||
```
|
||||
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 -->
|
||||
|
||||
|
||||
@@ -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
|
||||
the current function’s arguments in reverse.
|
||||
This is an alternative to `sed`, `awk`, `perl` and other tools. The
|
||||
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:**
|
||||
|
||||
```sh
|
||||
reverse_array() {
|
||||
# Usage: reverse_array "array"
|
||||
shopt -s extdebug
|
||||
f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
|
||||
shopt -u extdebug
|
||||
trim_string() {
|
||||
# Usage: trim_string " example string "
|
||||
: "${1#"${1%%[![:space:]]*}"}"
|
||||
: "${_%"${_##*[![:space:]]}"}"
|
||||
printf '%s\n' "$_"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ reverse_array 1 2 3 4 5
|
||||
5
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
$ trim_string " Hello, World "
|
||||
Hello, World
|
||||
|
||||
$ arr=(red blue green)
|
||||
$ reverse_array "${arr[@]}"
|
||||
green
|
||||
blue
|
||||
red
|
||||
$ name=" John Black "
|
||||
$ trim_string "$name"
|
||||
John Black
|
||||
```
|
||||
|
||||
## Remove duplicate array elements
|
||||
|
||||
Create a temporary associative array. When setting associative array
|
||||
values and a duplicate assignment occurs, bash overwrites the key. This
|
||||
allows us to effectively remove array duplicates.
|
||||
## 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
|
||||
remove_array_dups() {
|
||||
# Usage: remove_array_dups "array"
|
||||
declare -A tmp_array
|
||||
|
||||
for i in "$@"; do
|
||||
[[ "$i" ]] && IFS=" " tmp_array["${i:- }"]=1
|
||||
done
|
||||
|
||||
printf '%s\n' "${!tmp_array[@]}"
|
||||
lower() {
|
||||
# Usage: lower "string"
|
||||
printf '%s\n' "${1,,}"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
$ lower "HELLO"
|
||||
hello
|
||||
|
||||
$ arr=(red red green blue blue)
|
||||
$ remove_array_dups "${arr[@]}"
|
||||
red
|
||||
green
|
||||
blue
|
||||
$ lower "HeLlO"
|
||||
hello
|
||||
|
||||
$ lower "hello"
|
||||
hello
|
||||
```
|
||||
|
||||
## Random array element
|
||||
## Change a string to uppercase
|
||||
|
||||
**CAVEAT:** Requires `bash` 4+
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
random_array_element() {
|
||||
# Usage: random_array_element "array"
|
||||
local arr=("$@")
|
||||
printf '%s\n' "${arr[RANDOM % $#]}"
|
||||
upper() {
|
||||
# Usage: upper "string"
|
||||
printf '%s\n' "${1^^}"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ array=(red green blue yellow brown)
|
||||
$ random_array_element "${array[@]}"
|
||||
yellow
|
||||
$ upper "hello"
|
||||
HELLO
|
||||
|
||||
# You can also just pass multiple arguments.
|
||||
$ random_array_element 1 2 3 4 5 6 7
|
||||
3
|
||||
$ upper "HeLlO"
|
||||
HELLO
|
||||
|
||||
$ 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
|
||||
the print hits the last array element it starts from the first element
|
||||
again.
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
arr=(a b c d)
|
||||
|
||||
cycle() {
|
||||
printf '%s ' "${arr[${i:=0}]}"
|
||||
((i=i>=${#arr[@]}-1?0:++i))
|
||||
trim_quotes() {
|
||||
# Usage: trim_quotes "string"
|
||||
: "${1//\'}"
|
||||
printf '%s\n' "${_//\"}"
|
||||
}
|
||||
```
|
||||
|
||||
**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
|
||||
arr=(true false)
|
||||
|
||||
cycle() {
|
||||
printf '%s ' "${arr[${i:=0}]}"
|
||||
((i=i>=${#arr[@]}-1?0:++i))
|
||||
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 -->
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
## Simpler syntax to set variables
|
||||
|
||||
```shell
|
||||
# Clear screen on script exit.
|
||||
trap 'printf \\e[2J\\e[H\\e[m' EXIT
|
||||
# Simple math
|
||||
((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
|
||||
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
|
||||
# Set the value of var to var2 if var2 is greater than var.
|
||||
# var: variable to set.
|
||||
# var2>var: Condition to test.
|
||||
# ?var2: If the test succeeds.
|
||||
# :var: If the test fails.
|
||||
((var=var2>var?var2:var))
|
||||
```
|
||||
|
||||
<!-- 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
|
||||
# Disable unicode.
|
||||
LC_ALL=C
|
||||
LANG=C
|
||||
# Clear screen on script exit.
|
||||
trap 'printf \\e[2J\\e[H\\e[m' EXIT
|
||||
```
|
||||
|
||||
## 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 -->
|
||||
|
||||
@@ -1,51 +1,13 @@
|
||||
# Obsolete Syntax
|
||||
# Performance
|
||||
|
||||
## Shebang
|
||||
## Disable Unicode
|
||||
|
||||
Use `#!/usr/bin/env bash` instead of `#!/bin/bash`.
|
||||
|
||||
- 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.
|
||||
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.
|
||||
|
||||
```shell
|
||||
# Right:
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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() {
|
||||
# ...
|
||||
}
|
||||
# Disable unicode.
|
||||
LC_ALL=C
|
||||
LANG=C
|
||||
```
|
||||
|
||||
<!-- CHAPTER END -->
|
||||
|
||||
@@ -1,99 +1,51 @@
|
||||
# Internal Variables
|
||||
# Obsolete Syntax
|
||||
|
||||
**NOTE**: This list does not include every internal variable (*You can
|
||||
help by adding a missing entry!*).
|
||||
## Shebang
|
||||
|
||||
For a complete list, see:
|
||||
http://tldp.org/LDP/abs/html/internalvariables.html
|
||||
Use `#!/usr/bin/env bash` instead of `#!/bin/bash`.
|
||||
|
||||
## 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
|
||||
"$BASH"
|
||||
# Right:
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Wrong:
|
||||
|
||||
#!/bin/bash
|
||||
```
|
||||
|
||||
## Get the version of the current running `bash` process
|
||||
## Command Substitution
|
||||
|
||||
Use `$()` instead of `` ` ` ``.
|
||||
|
||||
```shell
|
||||
# As a string.
|
||||
"$BASH_VERSION"
|
||||
# Right.
|
||||
var="$(command)"
|
||||
|
||||
# As an array.
|
||||
"${BASH_VERSINFO[@]}"
|
||||
# Wrong.
|
||||
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
|
||||
"$EDITOR" "$file"
|
||||
# Right.
|
||||
do_something() {
|
||||
# ...
|
||||
}
|
||||
|
||||
# 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"
|
||||
# Wrong.
|
||||
function do_something() {
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
<!-- 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
|
||||
called.
|
||||
For a complete list, see:
|
||||
http://tldp.org/LDP/abs/html/internalvariables.html
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```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:**
|
||||
## Get the location to the `bash` binary
|
||||
|
||||
```shell
|
||||
# Output: LINES COLUMNS
|
||||
$ get_term_size
|
||||
15 55
|
||||
"$BASH"
|
||||
```
|
||||
|
||||
## Get the terminal size in pixels
|
||||
|
||||
**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:**
|
||||
## Get the version of the current running `bash` process
|
||||
|
||||
```shell
|
||||
# Output: WIDTHxHEIGHT
|
||||
$ get_window_size
|
||||
1200x800
|
||||
# As a string.
|
||||
"$BASH_VERSION"
|
||||
|
||||
# Output (fail):
|
||||
$ get_window_size
|
||||
x
|
||||
# As an array.
|
||||
"${BASH_VERSINFO[@]}"
|
||||
```
|
||||
|
||||
## Get the current cursor position
|
||||
|
||||
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:**
|
||||
## Open the user's preferred text editor
|
||||
|
||||
```shell
|
||||
# Output: X Y
|
||||
$ get_cursor_pos
|
||||
1 8
|
||||
"$EDITOR" "$file"
|
||||
|
||||
# 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 -->
|
||||
|
||||
@@ -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:**
|
||||
|
||||
```sh
|
||||
hex_to_rgb() {
|
||||
# Usage: hex_to_rgb "#FFFFFF"
|
||||
((r=16#${1:1:2}))
|
||||
((g=16#${1:3:2}))
|
||||
((b=16#${1:5:6}))
|
||||
get_term_size() {
|
||||
# Usage: get_term_size
|
||||
|
||||
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:**
|
||||
|
||||
```shell
|
||||
$ hex_to_rgb "#FFFFFF"
|
||||
255 255 255
|
||||
# Output: LINES COLUMNS
|
||||
$ 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:**
|
||||
|
||||
```sh
|
||||
rgb_to_hex() {
|
||||
# Usage: rgb_to_hex "r" "g" "b"
|
||||
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
|
||||
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
|
||||
$ rgb_to_hex "255" "255" "255"
|
||||
#FFFFFF
|
||||
# Output: WIDTHxHEIGHT
|
||||
$ 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
|
||||
# Tiny C Style.
|
||||
for((;i++<10;)){ echo "$i";}
|
||||
|
||||
# Undocumented method.
|
||||
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
|
||||
# ...
|
||||
```sh
|
||||
get_cursor_pos() {
|
||||
# Usage: get_cursor_pos
|
||||
IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
|
||||
printf '%s\n' "$x $y"
|
||||
}
|
||||
```
|
||||
|
||||
## 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.
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Modified snippet from Neofetch.
|
||||
case "$OSTYPE" in
|
||||
"darwin"*)
|
||||
: "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="$_"
|
||||
# Output: X Y
|
||||
$ get_cursor_pos
|
||||
1 8
|
||||
```
|
||||
|
||||
<!-- CHAPTER END -->
|
||||
|
||||
@@ -1,192 +1,150 @@
|
||||
# Other
|
||||
# Conversion
|
||||
|
||||
## 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+
|
||||
## Convert a hex color to RGB
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
read_sleep() {
|
||||
# Usage: sleep 1
|
||||
# sleep 0.2
|
||||
read -rst "${1:-1}" -N 999
|
||||
hex_to_rgb() {
|
||||
# Usage: hex_to_rgb "#FFFFFF"
|
||||
((r=16#${1:1:2}))
|
||||
((g=16#${1:3:2}))
|
||||
((b=16#${1:5:6}))
|
||||
|
||||
printf '%s\n' "$r $g $b"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
read_sleep 1
|
||||
read_sleep 0.1
|
||||
read_sleep 30
|
||||
$ hex_to_rgb "#FFFFFF"
|
||||
255 255 255
|
||||
```
|
||||
|
||||
## 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+
|
||||
## Convert an RGB color to hex
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
date() {
|
||||
# Usage: date "format"
|
||||
# See: 'man strftime' for format.
|
||||
printf "%($1)T\\n" "-1"
|
||||
rgb_to_hex() {
|
||||
# Usage: rgb_to_hex "r" "g" "b"
|
||||
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
|
||||
}
|
||||
```
|
||||
|
||||
**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
|
||||
$ rgb_to_hex "255" "255" "255"
|
||||
#FFFFFF
|
||||
```
|
||||
|
||||
## Generate a UUID V4
|
||||
|
||||
**Example Function:**
|
||||
# Code Golf
|
||||
|
||||
```sh
|
||||
uuid() {
|
||||
# Usage: uuid
|
||||
C="89ab"
|
||||
## Shorter `for` loop syntax
|
||||
|
||||
for ((N=0;N<16;++N)); do
|
||||
B="$((RANDOM%256))"
|
||||
```shell
|
||||
# Tiny C Style.
|
||||
for((;i++<10;)){ echo "$i";}
|
||||
|
||||
case "$N" in
|
||||
6) printf '4%x' "$((B%16))" ;;
|
||||
8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;;
|
||||
# Undocumented method.
|
||||
for i in {1..10};{ echo "$i";}
|
||||
|
||||
3|5|7|9)
|
||||
printf '%02x-' "$B"
|
||||
;;
|
||||
# Expansion.
|
||||
for i in {1..10}; do echo "$i"; done
|
||||
|
||||
*)
|
||||
printf '%02x' "$B"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# C Style.
|
||||
for((i=0;i<=10;i++)); do echo "$i"; done
|
||||
```
|
||||
|
||||
printf '\n'
|
||||
## 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
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
## 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
|
||||
$ uuid
|
||||
d5b6c731-1310-4c24-9fe3-55d556d44374
|
||||
```
|
||||
# Modified snippet from Neofetch.
|
||||
case "$OSTYPE" in
|
||||
"darwin"*)
|
||||
: "MacOS"
|
||||
;;
|
||||
|
||||
## Progress bars
|
||||
"linux"*)
|
||||
: "Linux"
|
||||
;;
|
||||
|
||||
This is a simple way of drawing progress bars without needing a for loop
|
||||
in the function itself.
|
||||
*"bsd"* | "dragonfly" | "bitrig")
|
||||
: "BSD"
|
||||
;;
|
||||
|
||||
**Example Function:**
|
||||
"cygwin" | "msys" | "win32")
|
||||
: "Windows"
|
||||
;;
|
||||
|
||||
```sh
|
||||
bar() {
|
||||
# Usage: bar 1 10
|
||||
# ^----- Elapsed Percentage (0-100).
|
||||
# ^-- Total length in chars.
|
||||
((elapsed=$1*$2/100))
|
||||
*)
|
||||
printf '%s\n' "Unknown OS detected, aborting..." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 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
|
||||
# Finally, set the variable.
|
||||
os="$_"
|
||||
```
|
||||
|
||||
<!-- 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
|
||||
# Loop from 0-100 (no variable support).
|
||||
for i in {0..100}; do
|
||||
printf '%s\n' "$i"
|
||||
done
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
reverse_array() {
|
||||
# Usage: reverse_array "array"
|
||||
shopt -s extdebug
|
||||
f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
|
||||
shopt -u extdebug
|
||||
}
|
||||
```
|
||||
|
||||
## Loop over a variable range of numbers
|
||||
|
||||
Don't use `seq`.
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Loop from 0-VAR.
|
||||
VAR=50
|
||||
for ((i=0;i<=VAR;i++)); do
|
||||
printf '%s\n' "$i"
|
||||
done
|
||||
$ reverse_array 1 2 3 4 5
|
||||
5
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
|
||||
$ arr=(red blue green)
|
||||
$ reverse_array "${arr[@]}"
|
||||
green
|
||||
blue
|
||||
red
|
||||
```
|
||||
|
||||
## Loop over an array
|
||||
## Remove duplicate array elements
|
||||
|
||||
```shell
|
||||
arr=(apples oranges tomatoes)
|
||||
Create a temporary associative array. When setting associative array
|
||||
values and a duplicate assignment occurs, bash overwrites the key. This
|
||||
allows us to effectively remove array duplicates.
|
||||
|
||||
# Just elements.
|
||||
for element in "${arr[@]}"; do
|
||||
printf '%s\n' "$element"
|
||||
done
|
||||
**CAVEAT:** Requires `bash` 4+
|
||||
|
||||
**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
|
||||
|
||||
printf '%s\n' "${!tmp_array[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
## Loop over an array with an index
|
||||
**Example Usage:**
|
||||
|
||||
```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.
|
||||
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
|
||||
$ arr=(red red green blue blue)
|
||||
$ remove_array_dups "${arr[@]}"
|
||||
red
|
||||
green
|
||||
blue
|
||||
```
|
||||
|
||||
## Loop over the contents of a file
|
||||
## Random array element
|
||||
|
||||
```shell
|
||||
while read -r line; do
|
||||
printf '%s\n' "$line"
|
||||
done < "file"
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
random_array_element() {
|
||||
# Usage: random_array_element "array"
|
||||
local arr=("$@")
|
||||
printf '%s\n' "${arr[RANDOM % $#]}"
|
||||
}
|
||||
```
|
||||
|
||||
## Loop over files and directories
|
||||
|
||||
Don’t use `ls`.
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Greedy example.
|
||||
for file in *; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
$ array=(red green blue yellow brown)
|
||||
$ random_array_element "${array[@]}"
|
||||
yellow
|
||||
|
||||
# PNG files in dir.
|
||||
for file in ~/Pictures/*.png; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
# You can also just pass multiple arguments.
|
||||
$ random_array_element 1 2 3 4 5 6 7
|
||||
3
|
||||
```
|
||||
|
||||
# Iterate over directories.
|
||||
for dir in ~/Downloads/*/; do
|
||||
printf '%s\n' "$dir"
|
||||
done
|
||||
## Cycle through an array
|
||||
|
||||
# Brace Expansion.
|
||||
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
Each time the `printf` is called, the next array element is printed. When
|
||||
the print hits the last array element it starts from the first element
|
||||
again.
|
||||
|
||||
# Iterate recursively.
|
||||
shopt -s globstar
|
||||
for file in ~/Pictures/**/*; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
shopt -u globstar
|
||||
```sh
|
||||
arr=(a b c d)
|
||||
|
||||
cycle() {
|
||||
printf '%s ' "${arr[${i:=0}]}"
|
||||
((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 -->
|
||||
|
||||
@@ -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
|
||||
|
||||
Alternative to the `cat` command.
|
||||
Don't use `seq`.
|
||||
|
||||
```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
|
||||
# Bash <4
|
||||
IFS=$'\n' read -d "" -ra file_data < "file"
|
||||
|
||||
# Bash 4+
|
||||
mapfile -t file_data < "file"
|
||||
# Loop from 0-VAR.
|
||||
VAR=50
|
||||
for ((i=0;i<=VAR;i++)); do
|
||||
printf '%s\n' "$i"
|
||||
done
|
||||
```
|
||||
|
||||
## Get the first N lines of a file
|
||||
|
||||
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:**
|
||||
## Loop over an array
|
||||
|
||||
```shell
|
||||
$ head 2 ~/.bashrc
|
||||
# Prompt
|
||||
PS1='➜ '
|
||||
arr=(apples oranges tomatoes)
|
||||
|
||||
$ head 1 ~/.bashrc
|
||||
# Prompt
|
||||
# Just elements.
|
||||
for element in "${arr[@]}"; do
|
||||
printf '%s\n' "$element"
|
||||
done
|
||||
```
|
||||
|
||||
## Get the last N lines of a file
|
||||
|
||||
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:**
|
||||
## Loop over an array with an index
|
||||
|
||||
```shell
|
||||
$ tail 2 ~/.bashrc
|
||||
# Enable tmux.
|
||||
# [[ -z "$TMUX" ]] && exec tmux
|
||||
arr=(apples oranges tomatoes)
|
||||
|
||||
$ tail 1 ~/.bashrc
|
||||
# [[ -z "$TMUX" ]] && exec tmux
|
||||
# Elements and index.
|
||||
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
|
||||
|
||||
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:**
|
||||
## Loop over the contents of a file
|
||||
|
||||
```shell
|
||||
$ lines ~/.bashrc
|
||||
48
|
||||
|
||||
$ lines_loop ~/.bashrc
|
||||
48
|
||||
while read -r line; do
|
||||
printf '%s\n' "$line"
|
||||
done < "file"
|
||||
```
|
||||
|
||||
## Count files or directories in directory
|
||||
## Loop over files and directories
|
||||
|
||||
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:**
|
||||
Don’t use `ls`.
|
||||
|
||||
```shell
|
||||
# Count all files in dir.
|
||||
$ count ~/Downloads/*
|
||||
232
|
||||
# Greedy example.
|
||||
for file in *; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
|
||||
# Count all dirs in dir.
|
||||
$ count ~/Downloads/*/
|
||||
45
|
||||
# PNG files in dir.
|
||||
for file in ~/Pictures/*.png; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
|
||||
# Count all jpg files in dir.
|
||||
$ count ~/Pictures/*.jpg
|
||||
64
|
||||
```
|
||||
# Iterate over directories.
|
||||
for dir in ~/Downloads/*/; do
|
||||
printf '%s\n' "$dir"
|
||||
done
|
||||
|
||||
## Create an empty file
|
||||
# Brace Expansion.
|
||||
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
|
||||
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...
|
||||
# Iterate recursively.
|
||||
shopt -s globstar
|
||||
for file in ~/Pictures/**/*; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
shopt -u globstar
|
||||
```
|
||||
|
||||
<!-- 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:**
|
||||
|
||||
```sh
|
||||
dirname() {
|
||||
# Usage: dirname "path"
|
||||
printf '%s\n' "${1%/*}/"
|
||||
head() {
|
||||
# Usage: head "n" "file"
|
||||
mapfile -tn "$1" line < "$2"
|
||||
printf '%s\n' "${line[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ dirname ~/Pictures/Wallpapers/1.jpg
|
||||
/home/black/Pictures/Wallpapers/
|
||||
$ head 2 ~/.bashrc
|
||||
# Prompt
|
||||
PS1='➜ '
|
||||
|
||||
$ dirname ~/Pictures/Downloads/
|
||||
/home/black/Pictures/
|
||||
$ head 1 ~/.bashrc
|
||||
# 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:**
|
||||
|
||||
```sh
|
||||
basename() {
|
||||
# Usage: basename "path"
|
||||
: "${1%/}"
|
||||
printf '%s\n' "${_##*/}"
|
||||
tail() {
|
||||
# Usage: tail "n" "file"
|
||||
mapfile -tn 0 line < "$2"
|
||||
printf '%s\n' "${line[@]: -$1}"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ basename ~/Pictures/Wallpapers/1.jpg
|
||||
1.jpg
|
||||
$ tail 2 ~/.bashrc
|
||||
# Enable tmux.
|
||||
# [[ -z "$TMUX" ]] && exec tmux
|
||||
|
||||
$ basename ~/Pictures/Downloads/
|
||||
Downloads
|
||||
$ tail 1 ~/.bashrc
|
||||
# [[ -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 -->
|
||||
|
||||
@@ -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
|
||||
hello_world="test"
|
||||
$ dirname ~/Pictures/Wallpapers/1.jpg
|
||||
/home/black/Pictures/Wallpapers/
|
||||
|
||||
# Create the variable name.
|
||||
var1="world"
|
||||
var2="hello_${var1}"
|
||||
$ dirname ~/Pictures/Downloads/
|
||||
/home/black/Pictures/
|
||||
```
|
||||
|
||||
# Print the value of the variable name stored in 'hello_$var1'.
|
||||
printf '%s\n' "${!var2}"
|
||||
## Get the base-name of a file path
|
||||
|
||||
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 -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
| 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. |
|
||||
|
||||
|
||||
## 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`.
|
||||
# Create the variable name.
|
||||
var1="world"
|
||||
var2="hello_${var1}"
|
||||
|
||||
# Print the value of the variable name stored in 'hello_$var1'.
|
||||
printf '%s\n' "${!var2}"
|
||||
```
|
||||
|
||||
<!-- 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? |
|
||||
| --------- | ---------------- |
|
||||
| `${!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`. |
|
||||
## Text Colors
|
||||
|
||||
**NOTE:** Sequences requiring RGB values only work in True-Color Terminal Emulators.
|
||||
|
||||
| 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? |
|
||||
| --------- | ---------------- |
|
||||
| `${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.
|
||||
|
||||
## 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+` |
|
||||
| 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. |
|
||||
|
||||
|
||||
## Default Value
|
||||
## Erasing Text
|
||||
|
||||
| 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.
|
||||
| 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`.
|
||||
|
||||
|
||||
<!-- CHAPTER END -->
|
||||
|
||||
@@ -1,42 +1,68 @@
|
||||
# Brace Expansion
|
||||
# Parameter Expansion
|
||||
|
||||
## Ranges
|
||||
## Indirection
|
||||
|
||||
```shell
|
||||
# Syntax: {<START>..<END>}
|
||||
| Parameter | What does it do? |
|
||||
| --------- | ---------------- |
|
||||
| `${!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.
|
||||
echo 1.{1..9}
|
||||
## Replacement
|
||||
|
||||
# Print chars a-z.
|
||||
echo {a..z}
|
||||
echo {A..Z}
|
||||
| Parameter | What does it do? |
|
||||
| --------- | ---------------- |
|
||||
| `${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.
|
||||
echo {A..Z}{0..9}
|
||||
## Length
|
||||
|
||||
# Print zero-padded numbers.
|
||||
# CAVEAT: bash 4+
|
||||
echo {01..100}
|
||||
| Parameter | What does it do? |
|
||||
| --------- | ---------------- |
|
||||
| `${#VAR}` | Length of var in characters.
|
||||
| `${#ARR[@]}` | Length of array in elements.
|
||||
|
||||
# Change increment amount.
|
||||
# Syntax: {<START>..<END>..<INCREMENT>}
|
||||
# CAVEAT: bash 4+
|
||||
echo {1..10..2} # Increment by 2.
|
||||
```
|
||||
## Expansion
|
||||
|
||||
## 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
|
||||
echo {apples,oranges,pears,grapes}
|
||||
## 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
|
||||
|
||||
| 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 -->
|
||||
|
||||
|
||||
@@ -1,30 +1,41 @@
|
||||
# Arithmetic
|
||||
# Brace Expansion
|
||||
|
||||
## Simpler syntax to set variables
|
||||
## Ranges
|
||||
|
||||
```shell
|
||||
# Simple math
|
||||
((var=1+2))
|
||||
# Syntax: {<START>..<END>}
|
||||
|
||||
# Decrement/Increment variable
|
||||
((var++))
|
||||
((var--))
|
||||
((var+=1))
|
||||
((var-=1))
|
||||
# Print numbers 1-100.
|
||||
echo {1..100}
|
||||
|
||||
# Using variables
|
||||
((var=var2*arr[2]))
|
||||
# Print range of floats.
|
||||
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
|
||||
# Set the value of var to var2 if var2 is greater than var.
|
||||
# var: variable to set.
|
||||
# var2>var: Condition to test.
|
||||
# ?var2: If the test succeeds.
|
||||
# :var: If the test fails.
|
||||
((var=var2>var?var2:var))
|
||||
echo {apples,oranges,pears,grapes}
|
||||
|
||||
# Example Usage:
|
||||
# Remove dirs Movies, Music and ISOS from ~/Downloads/.
|
||||
rm -rf ~/Downloads/{Movies,Music,ISOS}
|
||||
```
|
||||
|
||||
<!-- CHAPTER END -->
|
||||
|
||||
Reference in New Issue
Block a user