dylanaraps /
pure-bash-bible
📖 A collection of pure bash alternatives to external processes.
Loading repository data…
dylanaraps / repository
📖 A collection of pure POSIX sh alternatives to external processes.
The goal of this book is to document commonly-known and lesser-known methods of doing various tasks using only built-in POSIX sh features. Using the snippets from this bible can help remove unneeded dependencies from scripts and in most cases make them faster. I came across these tips and discovered a few while developing KISS Linux and other smaller projects.
The snippets below are all linted using shellcheck.
See something incorrectly described, buggy or outright wrong? Open an issue or send a pull request. If the bible is missing something, open an issue and a solution will be found.
Example Function:
lstrip() {
# Usage: lstrip "string" "pattern"
printf '%s\n' "${1##$2}"
}
Example Usage:
$ lstrip "The Quick Brown Fox" "The "
Quick Brown Fox
Example Function:
rstrip() {
# Usage: rstrip "string" "pattern"
printf '%s\n' "${1%%$2}"
}
Example Usage:
$ rstrip "The Quick Brown Fox" " Fox"
The Quick Brown
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.
Example Function:
trim_string() {
# Usage: trim_string " example string "
# Remove all leading white-space.
# '${1%%[![:space:]]*}': Strip everything but leading white-space.
# '${1#${XXX}}': Remove the white-space from the start of the string.
trim=${1#${1%%[![:space:]]*}}
# Remove all trailing white-space.
# '${trim##*[![:space:]]}': Strip everything but trailing white-space.
# '${trim%${XXX}}': Remove the white-space from the end of the string.
trim=${trim%${trim##*[![:space:]]}}
printf '%s\n' "$trim"
}
Example Usage:
$ trim_string " Hello, World "
Hello, World
$ name=" John Black "
$ trim_string "$name"
John Black
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:
# shellcheck disable=SC2086,SC2048
trim_all() {
# Usage: trim_all " example string "
# Disable globbing to make the word-splitting below safe.
set -f
# Set the argument list to the word-splitted string.
# This removes all leading/trailing white-space and reduces
# all instances of multiple spaces to a single (" " -> " ").
set -- $*
# Print the argument list as a string.
printf '%s\n' "$*"
# Re-enable globbing.
set +f
}
Example Usage:
$ trim_all " Hello, World "
Hello, World
$ name=" John Black is my name. "
$ trim_all "$name"
John Black is my name.
Using a case statement:
case $var in
*sub_string1*)
# Do stuff
;;
*sub_string2*)
# Do other stuff
;;
*)
# Else
;;
esac
Using a case statement:
case $var in
sub_string1*)
# Do stuff
;;
sub_string2*)
# Do other stuff
;;
*)
# Else
;;
esac
Using a case statement:
case $var in
*sub_string1)
# Do stuff
;;
*sub_string2)
# Do other stuff
;;
*)
# Else
;;
esac
This is an alternative to cut, awk and other tools.
Example Function:
split() {
# Disable globbing.
# This ensures that the word-splitting is safe.
set -f
# Store the current value of 'IFS' so we
# can restore it later.
old_ifs=$IFS
# Change the field separator to what we're
# splitting on.
IFS=$2
# Create an argument list splitting at each
# occurance of '$2'.
#
# This is safe to disable as it just warns against
# word-splitting which is the behavior we expect.
# shellcheck disable=2086
set -- $1
# Print each list value on its own line.
printf '%s\n' "$@"
# Restore the value of 'IFS'.
IFS=$old_ifs
# Re-enable globbing.
set +f
}
Example Usage:
$ split "apples,oranges,pears,grapes" ","
apples
oranges
pears
grapes
$ split "1, 2, 3, 4, 5" ", "
1
2
3
4
5
Example Function:
trim_quotes() {
# Usage: trim_quotes "string"
# Disable globbing.
# This makes the word-splitting below safe.
set -f
# Store the current value of 'IFS' so we
# can restore it later.
old_ifs=$IFS
# Set 'IFS' to ["'].
IFS=\"\'
# Create an argument list, splitting the
# string at ["'].
#
# Disable this shellcheck error as it only
# warns about word-splitting which we expect.
# shellcheck disable=2086
set -- $1
# Set 'IFS' to blank to remove spaces left
# by the removal of ["'].
IFS=
# Print the quote-less string.
printf '%s\n' "$*"
# Restore the value of 'IFS'.
IFS=$old_ifs
# Re-enable globbing.
set +f
}
Example Usage:
$ var="'Hello', \"World\""
$ trim_quotes "$var"
Hello, World
key=val file.This could be used to parse a simple key=value configuration file.
# Setting 'IFS' tells 'read' where to split the string.
while IFS='=' read -r key val; do
# Skip over lines containing comments.
# (Lines starting with '#').
[ "${key##\#*}" ] || continue
# '$key' stores the key.
# '$val' stores the value.
printf '%s: %s\n' "$key" "$val"
# Alternatively replacing 'printf' with the following
# populates variables called '$key' with the value of '$val'.
#
# NOTE: I would extend this with a check to ensure 'key' is
# a valid variable name.
# export "$key=$val"
#
# Example with error handling:
# export "$key=$val" 2>/dev/null ||
# printf 'warning %s is not a valid variable name\n' "$key"
done < "file"
Alternative to the head command.
Example Function:
head() {
# Usage: head "n" "file"
while IFS= read -r line; do
printf '%s\n' "$line"
i=$((i+1))
[ "$i" = "$1" ] && return
done < "$2"
# 'read' used in a loop will skip over
# the last line of a file if it does not contain
# a newline and instead contains EOF.
#
# The final line iteration is skipped as 'read'
# exits with '1' when it hits EOF. 'read' however,
# still populates the variable.
#
# This ensures that the final line is always printed
# if applicable.
[ -n "$line" ] && printf %s "$line"
}
Example Usage:
$ head 2 ~/.bashrc
# Prompt
PS1='➜ '
$ head 1 ~/.bashrc
# Prompt
Alternative to wc -l.
Example Function:
lines() {
# Usage: lines "file"
# '|| [ -n "$line" ]': This ensures that lines
# ending with EOL instead of a newline are still
# operated on in the loop.
#
# 'read' exits with '1' when it sees EOL and
# without the added test, the line isn't sent
# to the loop.
while IFS= read -r line || [ -n "$line" ]; do
lines=$((lines+1))
done < "$1"
printf '%s\n' "$lines"
Selected from shared topics, language and repository description—not editorial ratings.
dylanaraps /
📖 A collection of pure bash alternatives to external processes.