#!/usr/bin/env sh # printc(args, description) # Helper function to properly format text printc() { args="$1" cmd="$2" printf ' %s' "$1" yes '' | head -n "$((20-${#args}))" | tr \\n ' ' printf '%s' "$cmd" echo } # usage() # Display usage information usage() { echo "usage: tartar [-0..9] [--level N] [--format F] DIR" echo "Creates a compressed tape archive of every subdirectory in a given directory" echo echo "positional arguments:" printc "DIR" "the directory to archive" echo echo "parameters:" printc "-f, --format" "the compression format to use. default: xz" printf '%44s %s\n' "options: gzip, xz" printc "-0..-9, --level" "the level of compression to use: default 6" echo echo "environment variables:" printc "ARCHIVE_DIR" "same as positional argument DIR" printc "COMPRESSION_FORMAT" "same as --format" printc "COMPRESSION_LEVEL" "same as --level" } includes() { test="$1" shift for x in "$@"; do if test "$test" = "$x"; then return 0 fi done return 1 } FORMATS="gzip xz" LEVELS="0 1 2 3 4 5 6 7 8 9" COMPRESSION_FORMAT="xz" COMPRESSION_LEVEL="-6" set_format() { if includes "$1" "$FORMATS"; then COMPRESSION_FORMAT="$1" fi } set_level() { if includes "$1" "$LEVELS"; then COMPRESSION_LEVEL="-$1" fi } parse_args() { POSITIONAL_ARGS="" # parse args while [ $# -gt 0 ]; do case $1 in -f|--format) set_format "$2" shift shift ;; --level) set_level "$2" shift shift ;; -0|-1|-2|-3|-4|-5|-6|-7|-8|-9) COMPRESSION_LEVEL="$1" shift ;; -h|--help) usage exit 0 ;; *) POSITIONAL_ARGS="$POSITIONAL_ARGS $1" shift # past argument ;; esac done # drop the first space POSITIONAL_ARGS=$( echo "$POSITIONAL_ARGS" | tail -c +2 ) } can_archive() { if test ! -f "${1}/backup.done"; then echo "skipping $1; it is either incomplete or corrupted" return 1 fi if test ! -f "${1}/compression.done" || \ test ! -f "${1}.tar.xz" || \ ! sha1sum -sc "${1}/compression.done"; then return 0 else return 1 fi } parse_args "$@" # get the first positional argument, trim whitespace dir=$( echo "$POSITIONAL_ARGS" | cut -d' ' -f1 | xargs ) dir=${dir:-"$ARCHIVE_DIR"} cd "$dir" || exit 1 for dir in ./*/; do dir="${dir%*/}" if can_archive "$dir"; then fname="$(basename $dir).tar.xz" tar cv --exclude='*.done' "$dir" | "$COMPRESSION_FORMAT" "$COMPRESSION_LEVEL" > "$fname" sha1sum "$fname" > "${dir}/compression.done" fi done