#!/usr/bin/env bash # ------------------------------------------------------------------------------ # Copyright (c) 2013-2026 Geoffray Levasseur # Protected by the BSD3 license. Please read bellow for details. # # * Redistribution and use in source and binary forms, # * with or without modification, are permitted provided # * that the following conditions are met: # * # * Redistributions of source code must retain the above # * copyright notice, this list of conditions and the # * following disclaimer. # * # * Redistributions in binary form must reproduce the above # * copyright notice, this list of conditions and the following # * disclaimer in the documentation and/or other materials # * provided with the distribution. # * # * Neither the name of the copyright holder nor the names # * of any other contributors may be used to endorse or # * promote products derived from this software without # * specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # * OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Helpers for the option parsing of the commands. The project rule is to never # use eval: these functions rebuild argument lists in pure bash. # Split the output of getopt into the array whose name is $1, without eval and # without xargs. getopt prints the normalised arguments as one shell-quoted # line (options bare, every argument in single quotes, a quote inside an # argument written '\''), for instance: # -s 'a b' --long 'it'\''s' -- 'file' '' # Quoted text is taken verbatim (newlines included), an empty argument ('') # yields an empty element, and nothing is ever evaluated. The usual call is # local -a _pargs=() # _getopt_split _pargs "$PARSED" # set -- "${_pargs[@]}" # Usage: _getopt_split _getopt_split() { local -n _gs_out="$1" local s="$2" tok="" in_tok=0 run local run_re=$'^[^ \t\n\'\\\\]+' _gs_out=() while [[ -n "$s" ]]; do case "${s:0:1}" in "'") s="${s:1}" if [[ "$s" == *\'* ]]; then tok+="${s%%\'*}" s="${s#*\'}" else # Unterminated quote (never produced by getopt): keep the rest tok+="$s" s="" fi in_tok=1 ;; '\') tok+="${s:1:1}" s="${s:2}" in_tok=1 ;; ' '|$'\t'|$'\n') (( in_tok )) && _gs_out+=("$tok") tok="" in_tok=0 s="${s:1}" ;; *) [[ "$s" =~ $run_re ]] || break run="${BASH_REMATCH[0]}" tok+="$run" s="${s:${#run}}" in_tok=1 ;; esac done (( in_tok )) && _gs_out+=("$tok") return 0 } export -f _getopt_split # Put back traps saved with "trap -p" (one "trap -- 'command' SIGNAL" line per # trap), without eval. Used to restore the caller's traps after temporarily # replacing them. An empty argument restores nothing. # Usage: _trap_restore "$(trap -p INT TERM)" _trap_restore() { local line local -a w=() while IFS= read -r line; do [[ "$line" == "trap -- "* ]] || continue _getopt_split w "$line" # w = (trap -- ) [[ ${#w[@]} -eq 4 ]] && trap -- "${w[2]}" "${w[3]}" done <<< "$1" return 0 } export -f _trap_restore # ------------------------------------------------------------------------------ # EOF