2018-06-13 04:04:46 +02:00
|
|
|
|
<h1 align="center">pure bash</h1> <p align="center">A [WIP] collection of
|
|
|
|
|
pure bash alternatives to external processes.</p>
|
2018-06-13 03:51:15 +02:00
|
|
|
|
|
2018-06-13 04:04:46 +02:00
|
|
|
|
The goal of this repository is to document known and unknown methods of
|
|
|
|
|
doing various tasks using only built-in bash features. Using the snippets
|
|
|
|
|
from this guide can help to remove unneeded dependencies from your scripts
|
|
|
|
|
and in most cases make them that little bit faster. I came across these
|
|
|
|
|
tips and discovered a few while developing
|
|
|
|
|
[neofetch](https://github.com/dylanaraps/neofetch),
|
|
|
|
|
[pxltrm](https://github.com/dylanaraps/pxltrm) and some other smaller
|
|
|
|
|
projects.
|
|
|
|
|
|
|
|
|
|
This repository is open to contribution. If you see something that is
|
|
|
|
|
incorrectly described, buggy or outright wrong, open an issue or send a
|
|
|
|
|
pull request. If you know a handy snippet that is not included in this
|
|
|
|
|
list, send a pull request!
|
|
|
|
|
|
2018-06-13 04:39:10 +02:00
|
|
|
|
**NOTE**: Error handling (*checking if a file exists, etc*) is not
|
|
|
|
|
included. These are meant to be snippets you can incorporate into your
|
|
|
|
|
scripts and not full blown utilities.
|
|
|
|
|
|
2018-06-13 04:04:46 +02:00
|
|
|
|
|
|
|
|
|
## Table of Contents
|
2018-06-13 03:43:02 +02:00
|
|
|
|
|
|
|
|
|
<!-- vim-markdown-toc GFM -->
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [File handling](#file-handling)
|
2018-06-13 04:51:35 +02:00
|
|
|
|
* [Read a file to a string.](#read-a-file-to-a-string)
|
|
|
|
|
* [Read a file to an array (*by line*).](#read-a-file-to-an-array-by-line)
|
2018-06-13 04:37:07 +02:00
|
|
|
|
* [Get the first N lines of a file.](#get-the-first-n-lines-of-a-file)
|
|
|
|
|
* [Get the last N lines of a file.](#get-the-last-n-lines-of-a-file)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Get the number of lines in a file.](#get-the-number-of-lines-in-a-file)
|
2018-06-13 05:59:16 +02:00
|
|
|
|
* [Iterate over files.](#iterate-over-files)
|
2018-06-13 05:36:55 +02:00
|
|
|
|
* [Create an empty file.](#create-an-empty-file)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Strings](#strings)
|
2018-06-13 05:27:38 +02:00
|
|
|
|
* [Trim white-space from string.](#trim-white-space-from-string)
|
2018-06-13 05:17:25 +02:00
|
|
|
|
* [Split a string on a delimiter.](#split-a-string-on-a-delimiter)
|
2018-06-13 04:54:50 +02:00
|
|
|
|
* [Change a string to lowercase.](#change-a-string-to-lowercase)
|
|
|
|
|
* [Change a string to uppercase.](#change-a-string-to-uppercase)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Trim quotes from a string.](#trim-quotes-from-a-string)
|
2018-06-13 05:42:29 +02:00
|
|
|
|
* [Strip characters from start of string.](#strip-characters-from-start-of-string)
|
|
|
|
|
* [Strip characters from end of string.](#strip-characters-from-end-of-string)
|
2018-06-13 04:44:07 +02:00
|
|
|
|
* [Arrays](#arrays)
|
|
|
|
|
* [Reverse an array.](#reverse-an-array)
|
2018-06-13 05:21:42 +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)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Colors](#colors)
|
2018-06-13 04:37:07 +02:00
|
|
|
|
* [Convert a hex color to RGB.](#convert-a-hex-color-to-rgb)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Convert an RGB color to hex.](#convert-an-rgb-color-to-hex)
|
2018-06-13 05:17:25 +02:00
|
|
|
|
* [Information about the terminal.](#information-about-the-terminal)
|
|
|
|
|
* [Get the terminal size in lines and columns (*from a script*).](#get-the-terminal-size-in-lines-and-columns-from-a-script)
|
|
|
|
|
* [Get the terminal size in pixels.](#get-the-terminal-size-in-pixels)
|
|
|
|
|
* [Get the current cursor position.](#get-the-current-cursor-position)
|
2018-06-13 04:35:53 +02:00
|
|
|
|
* [Miscellaneous](#miscellaneous)
|
|
|
|
|
* [Get the current date using `strftime`.](#get-the-current-date-using-strftime)
|
2018-06-13 03:43:02 +02:00
|
|
|
|
|
|
|
|
|
<!-- vim-markdown-toc -->
|
2018-06-13 03:39:17 +02:00
|
|
|
|
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
## File handling
|
2018-06-13 03:39:17 +02:00
|
|
|
|
|
2018-06-13 04:51:35 +02:00
|
|
|
|
### Read a file to a string.
|
|
|
|
|
|
|
|
|
|
Alternative to the `cat` command.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
file_data="$(<"file")"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Read a file to an array (*by line*).
|
|
|
|
|
|
|
|
|
|
Alternative to the `cat` command.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
IFS=$'\n' read -d "" -ra file_data < "file"
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:37:07 +02:00
|
|
|
|
### Get the first N lines of a file.
|
2018-06-13 04:22:42 +02:00
|
|
|
|
|
|
|
|
|
Alternative to the `head` command.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
head() {
|
|
|
|
|
# Usage: head "n" "file"
|
|
|
|
|
mapfile -tn "$1" line < "$2"
|
|
|
|
|
printf '%s\n' "${line[@]}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:37:07 +02:00
|
|
|
|
### Get the last N lines of a file.
|
2018-06-13 04:22:42 +02:00
|
|
|
|
|
|
|
|
|
Alternative to the `tail` command.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
tail() {
|
|
|
|
|
# Usage: tail "n" "file"
|
|
|
|
|
mapfile -tn 0 line < "$2"
|
|
|
|
|
printf '%s\n' "${line[@]: -$1}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
### Get the number of lines in a file.
|
2018-06-13 04:31:24 +02:00
|
|
|
|
|
|
|
|
|
Alternative to `wc -l`.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
lines() {
|
|
|
|
|
# Usage lines "file"
|
|
|
|
|
mapfile -tn 0 lines < "$1"
|
|
|
|
|
printf '%s\n' "${#lines[@]}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:59:16 +02:00
|
|
|
|
### Iterate over files.
|
|
|
|
|
|
|
|
|
|
Don’t use `ls`.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
# Greedy example.
|
|
|
|
|
for file in *; do
|
|
|
|
|
echo "$file"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# PNG files in dir.
|
|
|
|
|
for file in ~/Pictures/*.png; do
|
|
|
|
|
echo "$file"
|
|
|
|
|
done
|
2018-06-13 06:02:50 +02:00
|
|
|
|
|
|
|
|
|
# Iterate over directories.
|
|
|
|
|
for dir in ~/Downloads/; do
|
|
|
|
|
echo "$dir"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# Iterate recursively.
|
|
|
|
|
shopt -s globstar
|
|
|
|
|
for file in ~/Pictures/**/*; do
|
|
|
|
|
echo "$file"
|
|
|
|
|
done
|
|
|
|
|
shopt -u globstar
|
2018-06-13 05:59:16 +02:00
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:36:55 +02:00
|
|
|
|
### Create an empty file.
|
|
|
|
|
|
|
|
|
|
Alternative to `touch`.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
:> file
|
|
|
|
|
|
|
|
|
|
# Longer alternatives:
|
|
|
|
|
echo -n > file
|
|
|
|
|
printf '' > file
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
|
|
|
|
|
## Strings
|
|
|
|
|
|
|
|
|
|
|
2018-06-13 05:27:38 +02:00
|
|
|
|
### Trim white-space from string.
|
|
|
|
|
|
|
|
|
|
**NOTE**: This also truncates multiple spaces inside the string.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
# shellcheck disable=SC2086,SC2048
|
|
|
|
|
trim() {
|
|
|
|
|
# Usage: trim " example string "
|
|
|
|
|
set -f
|
|
|
|
|
set -- $*
|
|
|
|
|
printf '%s\n' "$*"
|
|
|
|
|
set +f
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:17:25 +02:00
|
|
|
|
### Split a string on a delimiter.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
# To multiple variables.
|
|
|
|
|
string="1,2,3"
|
|
|
|
|
IFS=, read -r var1 var2 var3 <<< "$string"
|
|
|
|
|
|
|
|
|
|
# To an array.
|
|
|
|
|
IFS=, read -ra vars <<< "$string"
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:54:50 +02:00
|
|
|
|
### Change a string to lowercase.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
lower() {
|
|
|
|
|
# Usage: lower "string"
|
|
|
|
|
printf '%s\n' "${1,,}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Change a string to uppercase.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
upper() {
|
|
|
|
|
# Usage: upper "string"
|
|
|
|
|
printf '%s\n' "${1^^}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
### Trim quotes from a string.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
trim_quotes() {
|
|
|
|
|
# Usage: trim_quotes "string"
|
|
|
|
|
: "${1//\'}"
|
|
|
|
|
printf "%s\\n" "${_//\"}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:42:29 +02:00
|
|
|
|
### Strip characters from start of string.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
lstrip() {
|
|
|
|
|
# Usage: lstrip "string" "chars to remove"
|
|
|
|
|
printf '%s\n' "${1##$2}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Strip characters from end of string.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
rstrip() {
|
|
|
|
|
# Usage: rstrip "string" "chars to remove"
|
|
|
|
|
printf '%s\n' "${1%%$2}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:44:07 +02:00
|
|
|
|
## Arrays
|
|
|
|
|
|
|
|
|
|
### Reverse an array.
|
|
|
|
|
|
|
|
|
|
Enabling `extdebug` allows access to the `BASH_ARGV` array which stores
|
|
|
|
|
the current function’s arguments in reverse.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
reverse_array() {
|
|
|
|
|
# Usage: reverse_array "array"
|
|
|
|
|
# reverse_array 1 2 3 4 5 6
|
|
|
|
|
shopt -s extdebug
|
2018-06-13 04:45:08 +02:00
|
|
|
|
f()(printf '%s ' "${BASH_ARGV[@]}"); f "$@"
|
2018-06-13 04:44:07 +02:00
|
|
|
|
shopt -u extdebug
|
|
|
|
|
|
|
|
|
|
printf '\n'
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:21:42 +02:00
|
|
|
|
## File Paths
|
|
|
|
|
|
|
|
|
|
### Get the directory name of a file path.
|
|
|
|
|
|
|
|
|
|
Alternative to the `dirname` command.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
dirname() {
|
|
|
|
|
# Usage: dirname "path"
|
|
|
|
|
printf '%s\n' "${1%/*}/"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Get the base-name of a file path.
|
|
|
|
|
|
|
|
|
|
Alternative to the `basename` command.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
basename() {
|
|
|
|
|
# Usage: basename "path"
|
2018-06-13 05:42:29 +02:00
|
|
|
|
: "${1%/}"
|
|
|
|
|
printf '%s\n' "${_##*/}"
|
2018-06-13 05:21:42 +02:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
## Colors
|
|
|
|
|
|
2018-06-13 04:37:07 +02:00
|
|
|
|
### Convert a hex color to RGB.
|
2018-06-13 04:04:46 +02:00
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
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"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 04:35:53 +02:00
|
|
|
|
### Convert an RGB color to hex.
|
2018-06-13 04:04:46 +02:00
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
rgb_to_hex() {
|
|
|
|
|
# Usage: rgb_to_hex "r" "g" "b"
|
|
|
|
|
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:17:25 +02:00
|
|
|
|
## Information about the terminal.
|
2018-06-13 04:35:53 +02:00
|
|
|
|
|
2018-06-13 05:17:25 +02:00
|
|
|
|
### Get the terminal size in lines and columns (*from a script*).
|
2018-06-13 04:35:53 +02:00
|
|
|
|
|
|
|
|
|
This is handy when writing scripts in pure bash and `stty`/`tput` can’t be
|
|
|
|
|
called.
|
2018-06-13 03:39:17 +02:00
|
|
|
|
|
2018-06-13 04:21:50 +02:00
|
|
|
|
```sh
|
2018-06-13 04:35:53 +02:00
|
|
|
|
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"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-06-13 05:17:25 +02:00
|
|
|
|
### Get the terminal size in pixels.
|
|
|
|
|
|
|
|
|
|
**NOTE**: This does not work in some terminal emulators.
|
|
|
|
|
|
|
|
|
|
```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]}"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Get the current cursor position.
|
|
|
|
|
|
|
|
|
|
This is useful when creating a TUI in pure bash.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
get_cursor_pos() {
|
|
|
|
|
# Usage: get_cursor_pos
|
|
|
|
|
IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
|
|
|
|
|
printf '%s\n' "$x $y"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Miscellaneous
|
2018-06-13 04:35:53 +02:00
|
|
|
|
|
|
|
|
|
### 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.
|
|
|
|
|
|
|
|
|
|
**NOTE:** Requires `bash` 4+
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
date() {
|
|
|
|
|
# Usage: date "format"
|
|
|
|
|
# See: 'man strftime' for format.
|
|
|
|
|
printf "%($1)T\\n"
|
2018-06-13 04:21:50 +02:00
|
|
|
|
}
|
|
|
|
|
```
|