#!/bin/sh fname=$(basename "$0") usage() { echo "$fname Compile the target shell script into a single output Resolves '%include' lines with shell capacity" } # no arg unset infile if [ $# -lt 1 ] then if ! [ -t 0 ] then infile=/dev/stdin else usage && exit 1 fi fi [ -z "$TMPDIR" ] && TMPDIR=/tmp tmpdir="$TMPDIR/shcompile_$(tr -dc '[:alnum:]' < /dev/urandom | head -c10)" mkdir -p "$tmpdir" tmpfile="$tmpdir/ret" filelist="$tmpdir/list" headfile="$tmpdir/head" tailfile="$tmpdir/tail" stop() { rm -rf "$tmpdir" exit $1 } [ -z "$infile" ] && infile=$1 dirname=$() [ "$infile" = '-' ] && infile=/dev/stdin # create copy cat "$infile" > "$tmpfile" 2>&1 || { echo "Error: cannot read '$infile'" >&2 && stop 2; } # env when file [ "$infile" != "/dev/stdin" ] && { echo "$(readlink -f "$infile")" > "$filelist" cd "$(dirname "$infile")" } firstline=$(head -n1 "$tmpfile" | grep '^#!/') [ -z "$firstline" ] && firstline='#!/bin/sh' get_include_line() { grep -m1 -n '^%include ' "$1" | cut -d':' -f1 } n=$(get_include_line "$tmpfile") while [ -n "$n" ] do pre=$(head -n $((n-1)) "$tmpfile" > "$headfile") post=$(tail -n +$((n+1)) "$tmpfile" > "$tailfile") incarg=$(sed "$n""q;d" "$tmpfile" | cut -d ' ' -f2-) inc=$(echo "for I in $incarg ; do echo \$I ; done" | sh) cp "$headfile" "$tmpfile" echo "$inc" | while read -r file do cat "$file" >/dev/null 2>&1 || { echo "Error when trying to include '$incarg': '$file' could not be read" >&2 && stop 10; } if ! grep -q "^$(readlink -f "$file")\$" "$filelist" then # not already included cat "$file" >> "$tmpfile" echo "$(readlink -f "$file")" >> "$filelist" fi cd "$pwd" done cat "$tailfile" >> "$tmpfile" # get next include line n=$(get_include_line "$tmpfile") done which shfmt >/dev/null 2>&1 && shfmt -w -mn "$tmpfile" echo "$firstline" cat "$tmpfile" stop 0