Skip to main content

Bash functions to escape strings and make them safe for injection into a regex, or shell command.

#!/usr/bin/env bash

#
# Regex Quote
#
#     requote [string]
#
# Escape the argument string to make it safe for injection into a regex.
#
# The result is a regular expression that matches the literal argument
# string.
#
# https://github.com/lhunath/scripts/blob/master/bashlib/bashlib#L1362
requote() {

    # Initialize the defaults.
    local char

    printf '%s' "$1" | while IFS= read -r -d '' -n1 char; do
        printf '[%s]' "$char"
    done
}

#
# Shell Quote
#
#     shquote [-e] [argument...]
#
# Shell-quote the arguments to make them safe for injection into bash code.
#
# The result is bash code that represents a series of words, where each
# word is a literal string argument.  By default, quoting happens using
# single-quotes.
#
#   -e      Use backslashes rather than single quotes.
#   -d      Use double-quotes rather than single quotes (does NOT disable expansions!).
#   -a      Normally, shquote doesn't quote arguments that don't need it.  This forces all arguments to be quoted.
#
# https://github.com/lhunath/scripts/blob/master/bashlib/bashlib#L1316
shquote() {

    # Initialize the defaults.
    local OPTIND=1 arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single always=0

    # Parse the options.
    while getopts :eda arg; do
        case $arg in
            e) type=escape ;;
            d) type=double ;;
            a) always=1 ;;
        esac
    done
    shift "$((OPTIND - 1))"

    # Print out each argument, quoting it properly.
    for arg; do
        ((!always)) && [[ $arg == "$(printf %q "$arg")" ]] && quotedArgs+=("$arg") && continue

        case "$type" in
            escape)
                quotedArgs+=("$(printf "%q" "$arg")")
                ;;
            single)
                arg=${arg//"'"/$sq}
                quotedArgs+=("$(printf "'%s'" "$arg")")
                ;;
            double)
                arg=${arg//'"'/$dq}
                quotedArgs+=("$(printf '"%s"' "$arg")")
                ;;
        esac
    done

    printf '%s\n' "$(
        IFS=' '
        echo "${quotedArgs[*]}"
    )"
}