Convert Figma logo to code with AI

dylanaraps logopure-sh-bible

📖 A collection of pure POSIX sh alternatives to external processes.

6,448
280
6,448
33

Top Related Projects

ShellCheck, a static analysis tool for shell scripts

A curated list of awesome command-line frameworks, toolkits, guides and gizmos. Inspired by awesome-php.

Master the command line, in one page

A collection of small bash scripts for heavy terminal users

A curated list of delightful Bash scripts and resources.

14,241

:shell: Portable Unix shell commands for Node.js

Quick Overview

The pure-sh-bible is a collection of pure POSIX sh alternatives to external processes and programs. It aims to provide shell script snippets and functions that can replace common external commands, making shell scripts more portable and reducing dependencies on external tools.

Pros

  • Improves shell script portability across different UNIX-like systems
  • Reduces dependencies on external commands, potentially improving script execution speed
  • Provides educational value for learning shell scripting techniques
  • Offers a comprehensive collection of shell functions for various tasks

Cons

  • May be less efficient for complex operations compared to optimized external tools
  • Requires more code and maintenance compared to using built-in commands
  • Some functions might be less readable than their external command counterparts
  • Not suitable for all use cases, especially those requiring advanced features of external tools

Code Examples

  1. Trimming whitespace from a string:
trim() {
    set -f
    set -- $*
    printf '%s\n' "$*"
    set +f
}

# Usage
trimmed_string=$(trim "  Hello,   World!  ")
echo "$trimmed_string"  # Output: Hello, World!
  1. Generating a random number within a range:
random_range() {
    awk -v min="$1" -v max="$2" 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'
}

# Usage
random_num=$(random_range 1 100)
echo "Random number between 1 and 100: $random_num"
  1. Checking if a string contains a substring:
contains() {
    case "$1" in
        *"$2"*) return 0 ;;
        *)      return 1 ;;
    esac
}

# Usage
if contains "Hello, World!" "World"; then
    echo "String contains 'World'"
else
    echo "String does not contain 'World'"
fi

Getting Started

To use the pure-sh-bible in your shell scripts:

  1. Clone the repository:

    git clone https://github.com/dylanaraps/pure-sh-bible.git
    
  2. Source the desired function files in your script:

    #!/bin/sh
    . /path/to/pure-sh-bible/string.sh
    . /path/to/pure-sh-bible/math.sh
    
    # Now you can use the functions
    trimmed_string=$(trim "  Hello,   World!  ")
    echo "$trimmed_string"
    
  3. Alternatively, copy the specific functions you need directly into your script.

Competitor Comparisons

ShellCheck, a static analysis tool for shell scripts

Pros of ShellCheck

  • Provides real-time static analysis and linting for shell scripts
  • Offers integration with various text editors and CI/CD pipelines
  • Detects a wide range of potential issues and suggests fixes

Cons of ShellCheck

  • Focuses solely on error detection and doesn't provide educational content
  • May produce false positives or overly strict warnings in some cases

Code Comparison

ShellCheck example (detecting an issue):

if [ $foo = "bar" ]
# ShellCheck warning: Double quote to prevent globbing and word splitting

Pure Sh Bible example (educational content):

# Trim leading and trailing whitespace from a string.
trim() {
    : "${1#"${1%%[![:space:]]*}"}"
    : "${_%"${_##*[![:space:]]}"}"
    printf '%s\n' "$_"
}

Summary

ShellCheck is a powerful tool for detecting and preventing errors in shell scripts, offering real-time feedback and integration with various development environments. It excels at identifying potential issues but doesn't provide educational content.

Pure Sh Bible, on the other hand, serves as a comprehensive resource for shell scripting techniques and best practices. It offers a wealth of educational content and examples but doesn't provide automated error detection.

Both repositories serve different purposes and can be complementary in a shell developer's toolkit. ShellCheck ensures code quality and prevents errors, while Pure Sh Bible enhances knowledge and provides reusable snippets for common tasks.

A curated list of awesome command-line frameworks, toolkits, guides and gizmos. Inspired by awesome-php.

Pros of awesome-shell

  • Comprehensive collection of shell-related resources, tools, and frameworks
  • Regularly updated with community contributions
  • Covers a wide range of topics beyond just shell scripting

Cons of awesome-shell

  • Less focused on pure shell scripting techniques
  • May overwhelm beginners with the sheer number of options
  • Doesn't provide in-depth explanations or code examples

Code comparison

pure-sh-bible:

# Trim leading and trailing whitespace from a string
trim() {
    : "${1#"${1%%[![:space:]]*}"}"
    : "${_%"${_##*[![:space:]]}"}"
    printf '%s\n' "$_"
}

awesome-shell: No direct code examples provided, as it's a curated list of resources.

Summary

pure-sh-bible focuses on providing pure shell scripting techniques with detailed explanations and code examples. It's an excellent resource for those looking to improve their shell scripting skills without relying on external tools.

awesome-shell, on the other hand, is a comprehensive list of shell-related resources, tools, and frameworks. It covers a broader range of topics but doesn't provide in-depth explanations or code examples. It's more suitable for discovering new tools and resources rather than learning specific shell scripting techniques.

Master the command line, in one page

Pros of The Art of Command Line

  • Broader scope, covering various command-line tools and concepts beyond just shell scripting
  • More beginner-friendly with explanations and examples for each topic
  • Includes sections on system debugging, one-liners, and obscure but useful commands

Cons of The Art of Command Line

  • Less focused on pure shell scripting techniques
  • May not dive as deep into specific shell functionalities and optimizations
  • Updates less frequently compared to Pure Sh Bible

Code Comparison

The Art of Command Line:

# Find a command in your command history
history | grep "command"

# Run a command every 5 seconds
watch -n 5 command

Pure Sh Bible:

# Find a command in your command history
fc -ln 0 | grep "command"

# Run a command every 5 seconds
while :; do
    command
    sleep 5
done

Both repositories provide valuable resources for command-line users, but they serve different purposes. The Art of Command Line offers a comprehensive guide to various command-line tools and concepts, making it suitable for beginners and those looking for a broad overview. Pure Sh Bible, on the other hand, focuses specifically on shell scripting techniques and optimizations, making it more suitable for advanced users looking to improve their shell scripting skills.

A collection of small bash scripts for heavy terminal users

Pros of Bash-Snippets

  • Offers a collection of ready-to-use command-line tools for various tasks
  • Provides a user-friendly installation process with options for different package managers
  • Includes a wide range of functionalities, from weather forecasts to cryptocurrency prices

Cons of Bash-Snippets

  • Relies on external dependencies and APIs for some functionalities
  • May not be as portable or POSIX-compliant as Pure-sh-bible
  • Focuses more on specific tools rather than general shell scripting techniques

Code Comparison

Pure-sh-bible example (string manipulation):

trim_string() {
    : "${1#"${1%%[![:space:]]*}"}"
    : "${_%"${_##*[![:space:]]}"}"
    printf '%s\n' "$_"
}

Bash-Snippets example (from the weather script):

getIPWeather() {
  ip=$(curl -s ifconfig.co)
  curl -s "http://api.openweathermap.org/data/2.5/weather?q=$ip&units=imperial&appid=$API_KEY"
}

Pure-sh-bible focuses on shell scripting techniques without external dependencies, while Bash-Snippets provides specific tools that often utilize external APIs and services. Pure-sh-bible is more suitable for learning shell scripting fundamentals, while Bash-Snippets offers practical, ready-to-use utilities for various tasks.

A curated list of delightful Bash scripts and resources.

Pros of awesome-bash

  • Comprehensive collection of Bash resources, tools, and libraries
  • Regularly updated with community contributions
  • Covers a wide range of Bash-related topics, including scripting, command-line tools, and frameworks

Cons of awesome-bash

  • Less focused on pure Bash scripting techniques
  • May include outdated or less maintained resources
  • Requires more time to navigate and find specific information

Code Comparison

pure-sh-bible:

# String contains
if [[ $var == *sub_string* ]]; then
    printf '%s\n' "sub_string is in var."
fi

awesome-bash (example from a linked resource):

# String contains
if [[ "$string" == *"$substring"* ]]; then
    echo "Substring found"
fi

Summary

pure-sh-bible focuses on providing pure Bash scripting techniques and examples, offering a more concentrated resource for learning Bash scripting. It emphasizes POSIX-compliant solutions and aims to be a comprehensive reference for shell scripting.

awesome-bash, on the other hand, is a curated list of various Bash-related resources, including tools, libraries, and learning materials. It offers a broader scope but may require more effort to find specific information or techniques.

Both repositories are valuable for Bash enthusiasts, with pure-sh-bible being more suitable for those seeking pure Bash scripting knowledge, while awesome-bash provides a wider range of resources for Bash-related development and tooling.

14,241

:shell: Portable Unix shell commands for Node.js

Pros of ShellJS

  • Cross-platform compatibility: Works on Windows, macOS, and Linux
  • Provides a Node.js API for shell operations, making it easier for JavaScript developers
  • Extensive set of built-in commands and utilities

Cons of ShellJS

  • Requires Node.js runtime, not suitable for pure shell scripting environments
  • May have performance overhead compared to native shell commands
  • Limited to JavaScript syntax and ecosystem

Code Comparison

Pure Sh Bible example (checking if a directory exists):

if [ -d /path/to/dir ]; then
    echo "Directory exists"
else
    echo "Directory does not exist"
fi

ShellJS equivalent:

if (shell.test('-d', '/path/to/dir')) {
    console.log('Directory exists');
} else {
    console.log('Directory does not exist');
}

Summary

Pure Sh Bible focuses on providing pure shell scripting solutions, making it ideal for system administrators and developers working directly with shell environments. It offers a comprehensive collection of shell scripting techniques and best practices.

ShellJS, on the other hand, is designed for Node.js developers who want to leverage shell commands within their JavaScript applications. It provides a more familiar API for those coming from a JavaScript background and ensures cross-platform compatibility.

The choice between the two depends on the specific use case, development environment, and the team's expertise. Pure Sh Bible is better suited for traditional shell scripting, while ShellJS excels in Node.js-based projects requiring shell operations.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Also see: pure bash bible (📖 A collection of pure bash alternatives to external processes).


pure sh bible

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.

  • Leanpub book: (coming soon)
  • Buy me a coffee:

Table of Contents

STRINGS

Strip pattern from start of string

Example Function:

lstrip() {
    # Usage: lstrip "string" "pattern"
    printf '%s\n' "${1##$2}"
}

Example Usage:

$ lstrip "The Quick Brown Fox" "The "
Quick Brown Fox

Strip pattern from end of string

Example Function:

rstrip() {
    # Usage: rstrip "string" "pattern"
    printf '%s\n' "${1%%$2}"
}

Example Usage:

$ rstrip "The Quick Brown Fox" " Fox"
The Quick Brown

Trim leading and trailing white-space from string

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

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:

# 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.

Check if string contains a sub-string

Using a case statement:

case $var in
    *sub_string1*)
        # Do stuff
    ;;

    *sub_string2*)
        # Do other stuff
    ;;

    *)
        # Else
    ;;
esac

Check if string starts with sub-string

Using a case statement:

case $var in
    sub_string1*)
        # Do stuff
    ;;

    sub_string2*)
        # Do other stuff
    ;;

    *)
        # Else
    ;;
esac

Check if string ends with sub-string

Using a case statement:

case $var in
    *sub_string1)
        # Do stuff
    ;;

    *sub_string2)
        # Do other stuff
    ;;

    *)
        # Else
    ;;
esac

Split a string on a delimiter

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

Trim quotes from a string

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

FILES

Parsing a 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"

Get the first N lines of a 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

Get the number of lines in a file

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"
}

Example Usage:

$ 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:

count() {
    # Usage: count /path/to/dir/*
    #        count /path/to/dir/*/
    [ -e "$1" ] \
        && printf '%s\n' "$#" \
        || printf '%s\n' 0
}

Example Usage:

# 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.

:>file

# OR (shellcheck warns for this)
>file

FILE PATHS

Get the directory name of a file path

Alternative to the dirname command.

Example Function:

dirname() {
    # Usage: dirname "path"

    # If '$1' is empty set 'dir' to '.', else '$1'.
    dir=${1:-.}

    # Strip all trailing forward-slashes '/' from
    # the end of the string.
    #
    # "${dir##*[!/]}": Remove all non-forward-slashes
    # from the start of the string, leaving us with only
    # the trailing slashes.
    # "${dir%%"${}"}": Remove the result of the above
    # substitution (a string of forward slashes) from the
    # end of the original string.
    dir=${dir%%"${dir##*[!/]}"}

    # If the variable *does not* contain any forward slashes
    # set its value to '.'.
    [ "${dir##*/*}" ] && dir=.

    # Remove everything *after* the last forward-slash '/'.
    dir=${dir%/*}

    # Again, strip all trailing forward-slashes '/' from
    # the end of the string (see above).
    dir=${dir%%"${dir##*[!/]}"}

    # Print the resulting string and if it is empty,
    # print '/'.
    printf '%s\n' "${dir:-/}"
}

Example Usage:

$ 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:

basename() {
    # Usage: basename "path" ["suffix"]

    # Strip all trailing forward-slashes '/' from
    # the end of the string.
    #
    # "${1##*[!/]}": Remove all non-forward-slashes
    # from the start of the string, leaving us with only
    # the trailing slashes.
    # "${1%%"${}"}:  Remove the result of the above
    # substitution (a string of forward slashes) from the
    # end of the original string.
    dir=${1%${1##*[!/]}}

    # Remove everything before the final forward-slash '/'.
    dir=${dir##*/}

    # If a suffix was passed to the function, remove it from
    # the end of the resulting string.
    dir=${dir%"$2"}

    # Print the resulting string and if it is empty,
    # print '/'.
    printf '%s\n' "${dir:-/}"
}

Example Usage:

$ basename ~/Pictures/Wallpapers/1.jpg
1.jpg

$ basename ~/Pictures/Wallpapers/1.jpg .jpg
1

$ basename ~/Pictures/Downloads/
Downloads

LOOPS

Loop over a (small) range of numbers

Alternative to seq and only suitable for small and static number ranges. The number list can also be replaced with a list of words, variables etc.

# Loop from 0-10.
for i in 0 1 2 3 4 5 6 7 8 9 10; do
    printf '%s\n' "$i"
done

Loop over a variable range of numbers

Alternative to seq.

# Loop from var-var.
start=0
end=50

while [ "$start" -le "$end" ]; do
    printf '%s\n' "$start"
    start=$((start+1))
done

Loop over the contents of a file

while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line"
done < "file"

Loop over files and directories

Don’t use ls.

CAVEAT: When the glob does not match anything (empty directory or no matching files) the variable will contain the unexpanded glob. To avoid working on unexpanded globs check the existence of the file contained in the variable using the appropriate file conditional. Be aware that symbolic links are resolved.

# Greedy example.
for file in *; do
    [ -e "$file" ] || [ -L "$file" ] || continue
    printf '%s\n' "$file"
done

# PNG files in dir.
for file in ~/Pictures/*.png; do
    [ -f "$file" ] || continue
    printf '%s\n' "$file"
done

# Iterate over directories.
for dir in ~/Downloads/*/; do
    [ -d "$dir" ] || continue
    printf '%s\n' "$dir"
done

VARIABLES

Name and access a variable based on another variable

$ var="world"
$ eval "hello_$var=value"
$ eval printf '%s\n' "\$hello_$var"
value

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.

SequenceWhat does it do?Value
\033[38;5;<NUM>mSet text foreground color.0-255
\033[48;5;<NUM>mSet text background color.0-255
\033[38;2;<R>;<G>;<B>mSet text foreground color to RGB color.R, G, B
\033[48;2;<R>;<G>;<B>mSet text background color to RGB color.R, G, B

Text Attributes

SequenceWhat does it do?
\033[mReset text formatting and colors.
\033[1mBold text.
\033[2mFaint text.
\033[3mItalic text.
\033[4mUnderline text.
\033[5mSlow blink.
\033[7mSwap foreground and background colors.
\033[8mHidden text.
\033[9mStrike-through text.

Cursor Movement

SequenceWhat does it do?Value
\033[<LINE>;<COLUMN>HMove cursor to absolute position.line, column
\033[HMove cursor to home position (0,0).
\033[<NUM>AMove cursor up N lines.num
\033[<NUM>BMove cursor down N lines.num
\033[<NUM>CMove cursor right N columns.num
\033[<NUM>DMove cursor left N columns.num
\033[sSave cursor position.
\033[uRestore cursor position.

Erasing Text

SequenceWhat does it do?
\033[KErase from cursor position to end of line.
\033[1KErase from cursor position to start of line.
\033[2KErase the entire current line.
\033[JErase from the current line to the bottom of the screen.
\033[1JErase from the current line to the top of the screen.
\033[2JClear the screen.
\033[2J\033[HClear the screen and move cursor to 0,0.

PARAMETER EXPANSION

Prefix and Suffix Deletion

ParameterWhat 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

ParameterWhat does it do?
${#VAR}Length of var in characters.

Default Value

ParameterWhat 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.

CONDITIONAL EXPRESSIONS

For use in [ ] if [ ]; then and test.

File Conditionals

ExpressionValueWhat does it do?
-bfileIf file exists and is a block special file.
-cfileIf file exists and is a character special file.
-dfileIf file exists and is a directory.
-efileIf file exists.
-ffileIf file exists and is a regular file.
-gfileIf file exists and its set-group-id bit is set.
-hfileIf file exists and is a symbolic link.
-pfileIf file exists and is a named pipe (FIFO).
-rfileIf file exists and is readable.
-sfileIf file exists and its size is greater than zero.
-tfdIf file descriptor is open and refers to a terminal.
-ufileIf file exists and its set-user-id bit is set.
-wfileIf file exists and is writable.
-xfileIf file exists and is executable.
-LfileIf file exists and is a symbolic link.
-SfileIf file exists and is a socket.

Variable Conditionals

ExpressionValueWhat does it do?
-zvarIf the length of string is zero.
-nvarIf the length of string is non-zero.

Variable Comparisons

ExpressionWhat does it do?
var = var2Equal to.
var != var2Not equal to.
var -eq var2Equal to (algebraically).
var -ne var2Not equal to (algebraically).
var -gt var2Greater than (algebraically).
var -ge var2Greater than or equal to (algebraically).
var -lt var2Less than (algebraically).
var -le var2Less than or equal to (algebraically).

ARITHMETIC OPERATORS

Assignment

OperatorsWhat does it do?
=Initialize or change the value of a variable.

Arithmetic

OperatorsWhat does it do?
+Addition
-Subtraction
*Multiplication
/Division
%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

OperatorsWhat 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

OperatorsWhat does it do?
!NOT
&&AND
||OR

Miscellaneous

OperatorsWhat does it do?Example
,Comma Separator((a=1,b=2,c=3))

ARITHMETIC

Ternary Tests

# Set the value of var to var2 if var2 is greater than var.
# 'var2 > var': Condition to test.
# '? var2': If the test succeeds.
# ': var': If the test fails.
var=$((var2 > var ? var2 : var))

Check if a number is a float

Example Function:

is_float() {
    # Usage: is_float "number"

    # The test checks to see that the input contains
    # a '.'. This filters out whole numbers.
    [ -z "${1##*.*}" ] &&
        printf %f "$1" >/dev/null 2>&1
}

Example Usage:

$ is_float 1 && echo true
$

$ is_float 1.1 && echo true
$ true

Check if a number is an integer

Example Function:

is_int() {
    # usage: is_int "number"
    printf %d "$1" >/dev/null 2>&1
}

Example Usage:

$ is_int 1 && echo true
$ true

$ is_int 1.1 && echo true
$

TRAPS

Traps allow a script to execute code on various signals. In pxltrm (a pixel art editor written in bash) traps are used to redraw the user interface on window resize. Another use case is cleaning up temporary files on script exit.

Traps should be added near the start of scripts so any early errors are also caught.

Do something on script exit

# Clear screen on script exit.
trap 'printf \\033[2J\\033[H\\033[m' EXIT

# Run a function on script exit.
# 'clean_up' is the name of a function.
trap clean_up EXIT

Ignore terminal interrupt (CTRL+C, SIGINT)

trap '' INT

OBSOLETE SYNTAX

Command Substitution

Use $() instead of ` `.

# Right.
var="$(command)"

# Wrong.
var=`command`

# $() can easily be nested whereas `` cannot.
var="$(command "$(command)")"

INTERNAL AND ENVIRONMENT VARIABLES

Open the user's preferred text editor

"$EDITOR" "$file"

# NOTE: This variable may be empty, set a fallback value.
"${EDITOR:-vi}" "$file"

Get the current working directory

This is an alternative to the pwd built-in.

"$PWD"

Get the PID of the current shell

"$$"

Get the current shell options

"$-"

AFTERWORD

Thanks for reading! If this bible helped you in any way and you'd like to give back, consider donating. Donations give me the time to make this the best resource possible. Can't donate? That's OK, star the repo and share it with your friends!

Rock on. 🤘