Pure Bash Bible

repository·master·Indexed 12 days ago

https://github.com/dylanaraps/pure-bash-bible

A collection of pure bash alternatives to external processes such as sed, awk, perl, cut, head, tail, and dirname. Designed to increase script speed and reduce environment dependencies, these snippets include implementations for string manipulation, array operations, file reading, and ANSI escape sequences for terminal formatting.

Tokens
7.4K
Snippets
38
Records
44
Agent score
49%

What's inside Pure Bash Bible

  1. Overview of pure bash bible

    master

    The pure-bash-bible is a collection of pure bash alternatives to external processes (like sed, awk, or perl). Using these built-in methods can make scripts faster by reducing the overhead of calling external programs and helps remove unnecessary dependencies from your environment.

    All snippets are linted with shellcheck and include tests where applicable.

  2. Perform arithmetic operations with (( ))

    master

    Use the double-parentheses (( )) syntax for efficient arithmetic and variable assignment in Bash. This avoids calling external processes like expr or bc.

    Supported Operators

    Arithmetic

    • + (Addition), - (Subtraction), * (Multiplication), / (Division), ** (Exponentiation), % (Modulo)
    • +=, -=, *=, /=, %= (Compound assignment)

    Bitwise

    • <<, >> (Shifts), & (AND), | (OR), ~ (NOT), ^ (XOR)
    • <<=, >>=, &=, |=, ^= (Compound bitwise assignment)

    Logical

    • !, &&, ||

    Miscellaneous

    • , (Comma separator for multiple assignments, e.g., ((a=1,b=2)))

    Assignment

    • = (Initialize or change value)
    # Simple math
    ((var=1+2))
    
    # Increment/Decrement
    ((var++))
    ((var--))
    ((var+=1))
    
    # Using variables
    ((var=var2*arr[2]))
  3. Get the current date using `printf` strftime

    master

    Bash's printf can format dates using strftime syntax, removing the need for the date command.

    Note: Requires Bash 4+.

    # Function wrapper
    date() {
        printf "%($1)T\n" "-1"
    }
    
    # Direct usage
    printf '%(%a %d %b  - %l:%M %p)T\n' "-1"
    
    # Assigning to a variable
    printf -v date '%(%a %d %b  - %l:%M %p)T\n' '-1'
  4. Get terminal size and cursor position in pure Bash

    master

    If stty or tput are unavailable, you can use these pure Bash functions to interact with the terminal.

    # Get terminal size in lines and columns
    get_term_size() {
        shopt -s checkwinsize; (:;:) 
        printf '%s\n' "$LINES $COLUMNS"
    }
    
    # Get terminal size in pixels (Caveat: may not work in all emulators)
    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\nx%s' "${term_size[1]}" "${term_size[2]}"
    }
    
    # Get current cursor position (X Y)
    get_cursor_pos() {
        IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
        printf '%s %s' "$x" "$y"
    }
  5. Follow best practices for obsolete syntax

    master

    To ensure maximum compatibility and follow modern standards, avoid these older patterns:

    • Shebang: Use #!/usr/bin/env bash instead of #!/bin/bash to find the binary in the user's PATH.
    • Command Substitution: Use $(command) instead of `command`. The $() syntax supports nesting.
    • Function Declaration: Use name() { ... } instead of function name { ... } to maintain compatibility with older Bash versions.
    # Right: Shebang
    #!/usr/bin/env bash
    
    # Right: Command Substitution
    var="$(command)"
    
    # Right: Function Declaration
    do_something() {
        # ...
    }
  6. Use traps to execute code on signals

    master

    The trap command allows you to execute specific code when the shell receives certain signals. This is useful for cleanup or UI updates.

    SignalUse Case
    EXITRun code when the script exits (e.g., clearing the screen)
    INTHandle terminal interrupts (CTRL+C)
    SIGWINCHReact to window resizing
    DEBUGRun code before every command
    RETURNRun code when a function or sourced file finishes
    # Clear screen on script exit.
    trap 'printf \e[2J\e[H\e[m' EXIT
    
    # Ignore terminal interrupt (CTRL+C, SIGINT)
    trap '' INT
    
    # Call a function on window resize.
    trap 'code_here' SIGWINCH
    
    # Do something before every command
    trap 'code_here' DEBUG
    
    # Do something when a shell function finishes
    trap 'code_here' RETURN
  7. Use `read` as a pure Bash alternative to `sleep`

    master

    The sleep command is an external process. For high-performance scripts, use read -t to implement a delay.

    Note: Requires Bash 4+.

    # Basic usage
    read_sleep() {
        read -rt "$1" <> <(:) || :
    }
    
    # High-performance loop (avoids repeated FD allocation)
    exec {sleep_fd}<> <(:)
    while some_quick_test; do
        read -t 0.001 -u $sleep_fd
    done
  8. Change string case (lower, upper, reverse)

    master

    Bash 4+ built-in parameter expansion alternatives for case manipulation.

    • Lower: ${1,,}
    • Upper: ${1^^}
    • Reverse: ${1~~}
    # Lowercase
    lower() {
        printf '%s\n' "${1,,}"
    }
    
    # Uppercase
    upper() {
        printf '%s\n' "${1^^}"
    }
    
    # Reverse case
    reverse_case() {
        printf '%s\n' "${1~~}"
    }

    Usage:

    $ lower "HELLO" hello $ upper "hello" HELLO $ reverse_case "HeLlO" hElLo

  9. Get the directory name of a file path

    master

    Alternative to the dirname command. This function parses a path string to return the parent directory.

    dirname() {
        # Usage: dirname "path"
        local tmp=${1:-.}
    
        [[ $tmp != *[!/]* ]] && {
            printf '/\n'
            return
        }
    
        tmp=${tmp%%"${tmp##*[!/]}"}
    
        [[ $tmp != */* ]] && {
            printf '.\n'
            return
        }
    
        tmp=${tmp%/*}
        tmp=${tmp%%"${tmp##*[!/]}"}
    
        printf '%s\n' "${tmp:-/}"
    }
  10. Get the number of lines in a file

    master

    Alternative to wc -l. There are two primary methods depending on your Bash version and file size requirements.

    Bash 4+ (Fastest)

    Uses mapfile to read the file into an array and then prints the array length.

    Bash 3+ (Memory Efficient)

    Uses a while loop to iterate through the file. This is slower for large files but uses significantly less memory than the mapfile method.

    # Bash 4+ method
    lines() {
        mapfile -tn 0 lines < "$1"
        printf '%s\n' "${#lines[@]}"
    }
    
    # Bash 3 method (Memory efficient)
    lines_loop() {
        count=0
        while IFS= read -r _; do
            ((count++))
        done < "$1"
        printf '%s\n' "$count"
    }