361 lines
7.1 KiB
Markdown
361 lines
7.1 KiB
Markdown
# pure sh bible
|
|
|
|
A collection of pure POSIX `sh` alternatives to external processes
|
|
|
|
|
|
## Table of Contents
|
|
|
|
<!-- vim-markdown-toc GFM -->
|
|
|
|
* [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)
|
|
* [Trim all white-space from string and truncate spaces](#trim-all-white-space-from-string-and-truncate-spaces)
|
|
* [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)
|
|
* [FILES](#files)
|
|
* [Get the first N lines of a file](#get-the-first-n-lines-of-a-file)
|
|
* [Get the number of lines in a file](#get-the-number-of-lines-in-a-file)
|
|
* [Count files or directories in directory](#count-files-or-directories-in-directory)
|
|
* [Create an empty file](#create-an-empty-file)
|
|
* [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)
|
|
* [ESCAPE SEQUENCES](#escape-sequences)
|
|
* [Text Colors](#text-colors)
|
|
* [Text Attributes](#text-attributes)
|
|
* [Cursor Movement](#cursor-movement)
|
|
* [Erasing Text](#erasing-text)
|
|
|
|
<!-- vim-markdown-toc -->
|
|
|
|
|
|
# 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
|
|
```
|
|
|
|
## 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.
|
|
```
|
|
|
|
## 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
|
|
```
|
|
|
|
# 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
|
|
```
|
|
|
|
## 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
|
|
```
|
|
|
|
## 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
|
|
```
|
|
|
|
# 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
|
|
```
|
|
|
|
# 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`.
|
|
|
|
|