pure-sh-bible/README.md

509 lines
12 KiB
Markdown
Raw Normal View History

2019-09-19 09:36:16 +02:00
# pure sh bible
A collection of pure POSIX `sh` alternatives to external processes
2019-09-19 10:56:39 +02:00
**NOTE**: If anything seen here is **not** POSIX `sh`, open an issue. This is a living document that is open to change and improvement.
2019-09-19 09:36:16 +02:00
## Table of Contents
<!-- vim-markdown-toc GFM -->
2019-09-19 09:56:28 +02:00
* [STRINGS](#strings)
* [Strip pattern from start of string](#strip-pattern-from-start-of-string)
* [Strip pattern from end of string](#strip-pattern-from-end-of-string)
2019-09-19 09:58:29 +02:00
* [Trim all white-space from string and truncate spaces](#trim-all-white-space-from-string-and-truncate-spaces)
2019-09-19 10:01:21 +02:00
* [Check if string contains a sub-string](#check-if-string-contains-a-sub-string)
* [Check if string starts with sub-string](#check-if-string-starts-with-sub-string)
* [Check if string ends with sub-string](#check-if-string-ends-with-sub-string)
2019-09-19 10:22:33 +02:00
* [FILES](#files)
* [Get the first N lines of a file](#get-the-first-n-lines-of-a-file)
2019-09-19 10:30:09 +02:00
* [Get the number of lines in a file](#get-the-number-of-lines-in-a-file)
2019-09-19 10:33:53 +02:00
* [Count files or directories in directory](#count-files-or-directories-in-directory)
* [Create an empty file](#create-an-empty-file)
2019-09-19 10:36:27 +02:00
* [FILE PATHS](#file-paths)
* [Get the directory name of a file path](#get-the-directory-name-of-a-file-path)
* [Get the base-name of a file path](#get-the-base-name-of-a-file-path)
2019-09-19 10:42:19 +02:00
* [ESCAPE SEQUENCES](#escape-sequences)
* [Text Colors](#text-colors)
* [Text Attributes](#text-attributes)
* [Cursor Movement](#cursor-movement)
* [Erasing Text](#erasing-text)
2019-09-19 10:45:48 +02:00
* [PARAMETER EXPANSION](#parameter-expansion)
* [Replacement](#replacement)
* [Length](#length)
* [Default Value](#default-value)
2019-09-19 10:52:26 +02:00
* [CONDITIONAL EXPRESSIONS](#conditional-expressions)
* [File Conditionals](#file-conditionals)
* [Variable Conditionals](#variable-conditionals)
* [Variable Comparisons](#variable-comparisons)
2019-09-19 10:56:39 +02:00
* [ARITHMETIC OPERATORS](#arithmetic-operators)
* [Assignment](#assignment)
* [Arithmetic](#arithmetic)
* [Bitwise](#bitwise)
* [Logical](#logical)
* [Miscellaneous](#miscellaneous)
2019-09-19 09:56:28 +02:00
2019-09-19 09:36:16 +02:00
<!-- vim-markdown-toc -->
2019-09-19 09:56:28 +02:00
# STRINGS
## 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
```
2019-09-19 09:58:29 +02:00
## 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.
```
2019-09-19 10:01:21 +02:00
## Check if string contains a sub-string
**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
**Using a case statement:**
```shell
case $var in
sub_string*)
# Do stuff
;;
sub_string2*)
# Do more stuff
;;
*)
# Else
;;
esac
```
## Check if string ends with sub-string
**Using a case statement:**
```shell
case $var in
*sub_string)
# Do stuff
;;
*sub_string2)
# Do more stuff
;;
*)
# Else
;;
esac
```
2019-09-19 10:22:33 +02:00
# FILES
## Get the first N lines of a file
Alternative to the `head` command.
**Example Function:**
```sh
head() {
# Usage: head "n" "file"
while read -r line; do
[ "$i" = "$1" ] && break
printf '%s\n' "$line"
i=$((i+1))
done < "$2"
}
```
**Example Usage:**
```shell
$ head 2 ~/.bashrc
# Prompt
PS1='➜ '
$ head 1 ~/.bashrc
# Prompt
```
2019-09-19 10:30:09 +02:00
## Get the number of lines in a file
Alternative to `wc -l`.
**Example Function:**
```sh
lines() {
# Usage: lines "file"
while read -r _; do
lines=$((lines+1))
done < "$1"
printf '%s\n' "$lines"
}
```
**Example Usage:**
```shell
$ lines ~/.bashrc
48
```
2019-09-19 10:33:53 +02:00
## Count files or directories in directory
This works by passing the output of the glob to the function and then counting the number of arguments.
**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
:>file
# OR (shellcheck warns for this)
>file
```
2019-09-19 10:36:27 +02:00
# FILE PATHS
## 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
$ dirname ~/Pictures/Wallpapers/1.jpg
/home/black/Pictures/Wallpapers/
$ dirname ~/Pictures/Downloads/
/home/black/Pictures/
```
## Get the base-name of a file path
Alternative to the `basename` command.
**Example Function:**
```sh
basename() {
# Usage: basename "path"
path=${1%/}
printf '%s\n' "${path##*/}"
}
```
**Example Usage:**
```shell
$ basename ~/Pictures/Wallpapers/1.jpg
1.jpg
$ basename ~/Pictures/Downloads/
Downloads
```
2019-09-19 10:42:19 +02:00
# ESCAPE SEQUENCES
Contrary to popular belief, there is no issue in utilizing raw escape sequences. Using `tput` abstracts the same ANSI sequences as if printed manually. Worse still, `tput` is not actually portable. There are a number of `tput` variants each with different commands and syntaxes (*try `tput setaf 3` on a FreeBSD system*). Raw sequences are fine.
## 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. |
## 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`.
2019-09-19 10:45:48 +02:00
# PARAMETER EXPANSION
## Replacement
| 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. |
## Length
| Parameter | What does it do? |
| --------- | ---------------- |
| `${#VAR}` | Length of var in characters.
## Default Value
| Parameter | What does it do? |
| --------- | ---------------- |
| `${VAR:-STRING}` | If `VAR` is empty or unset, use `STRING` as its value.
| `${VAR-STRING}` | If `VAR` is unset, use `STRING` as its 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` is not empty, use `STRING` as its value.
| `${VAR+STRING}` | If `VAR` is set, use `STRING` as its value.
| `${VAR:?STRING}` | Display an error if empty or unset.
| `${VAR?STRING}` | Display an error if unset.
2019-09-19 10:52:26 +02:00
# CONDITIONAL EXPRESSIONS
2019-09-19 10:53:47 +02:00
For use in `[ ]` `if [ ]; then` and `test`.
2019-09-19 10:52:26 +02:00
## File Conditionals
| Expression | Value | What does it do? |
| ---------- | ------ | ---------------- |
| `-b` | `file` | If file exists and is a block special file.
| `-c` | `file` | If file exists and is a character special file.
| `-d` | `file` | If file exists and is a directory.
| `-e` | `file` | If file exists.
| `-f` | `file` | If file exists and is a regular file.
| `-g` | `file` | If file exists and its set-group-id bit is set.
| `-h` | `file` | If file exists and is a symbolic link.
| `-p` | `file` | If file exists and is a named pipe (*FIFO*).
| `-r` | `file` | If file exists and is readable.
| `-s` | `file` | If file exists and its size is greater than zero.
| `-t` | `fd` | If file descriptor is open and refers to a terminal.
| `-u` | `file` | If file exists and its set-user-id bit is set.
| `-w` | `file` | If file exists and is writable.
| `-x` | `file` | If file exists and is executable.
| `-L` | `file` | If file exists and is a symbolic link.
| `-S` | `file` | If file exists and is a socket.
## Variable Conditionals
| Expression | Value | What does it do? |
| ---------- | ----- | ---------------- |
| `-z` | `var` | If the length of string is zero.
| `-n` | `var` | If the length of string is non-zero.
## Variable Comparisons
| Expression | What does it do? |
| ---------- | ---------------- |
| `var = var2` | Equal to.
| `var != var2` | Not equal to.
| `var -eq var2` | Equal to (*algebraically*).
| `var -ne var2` | Not equal to (*algebraically*).
| `var -gt var2` | Greater than (*algebraically*).
| `var -ge var2` | Greater than or equal to (*algebraically*).
| `var -lt var2` | Less than (*algebraically*).
| `var -le var2` | Less than or equal to (*algebraically*).
2019-09-19 10:56:39 +02:00
# ARITHMETIC OPERATORS
## Assignment
| Operators | What does it do? |
| --------- | ---------------- |
| `=` | Initialize or change the value of a variable.
## Arithmetic
| Operators | What does it do? |
| --------- | ---------------- |
| `+` | Addition
| `-` | Subtraction
| `*` | Multiplication
| `/` | Division
| `**` | Exponentiation
| `%` | Modulo
| `+=` | Plus-Equal (*Increment a variable.*)
| `-=` | Minus-Equal (*Decrement a variable.*)
| `*=` | Times-Equal (*Multiply a variable.*)
| `/=` | Slash-Equal (*Divide a variable.*)
| `%=` | Mod-Equal (*Remainder of dividing a variable.*)
## Bitwise
| Operators | What does it do? |
| --------- | ---------------- |
| `<<` | Bitwise Left Shift
| `<<=` | Left-Shift-Equal
| `>>` | Bitwise Right Shift
| `>>=` | Right-Shift-Equal
| `&` | Bitwise AND
| `&=` | Bitwise AND-Equal
| `\|` | Bitwise OR
| `\|=` | Bitwise OR-Equal
| `~` | Bitwise NOT
| `^` | Bitwise XOR
| `^=` | Bitwise XOR-Equal
## Logical
| Operators | What does it do? |
| --------- | ---------------- |
| `!` | NOT
| `&&` | AND
| `\|\|` | OR
## Miscellaneous
| Operators | What does it do? | Example |
| --------- | ---------------- | ------- |
| `,` | Comma Separator | `((a=1,b=2,c=3))`