M archives/Makefile => archives/Makefile +6 -0
@@ 15,6 15,9 @@ install:
install -m755 untar $(BIN_DIR)/untar
install -m755 zipls $(BIN_DIR)/zipls
+ install -m755 archive.bash $(LIB_DIR)/archive.bash
+ install -m755 unarchive.bash $(LIB_DIR)/unarchive.bash
+
install -m755 completion.bash $(COMP_DIR)/myutils_archives.bash
uninstall:
@@ 28,6 31,9 @@ uninstall:
rm $(BIN_DIR)/untar
rm $(BIN_DIR)/zipls
+ rm $(LIB_DIR)/archive.bash
+ rm $(LIB_DIR)/unarchive.bash
+
rm $(COMP_DIR)/myutils_archives.bash
test: clean
M archives/README.md => archives/README.md +18 -5
@@ 11,19 11,32 @@ expect `tar` to support Zstandard, which isn't necessarily POSIX standard.*
Executable |Description |Extra Dependencies
:---------------|:-------------------------------------------------------------|:------------------------------------------
epub |Dumps HTML from an 'epub' e-book archive |`bash`, `zipinfo`, `unzip`, `w3m`
-mktar |Archive utility |`bash`
-mktar-batch |Archive utility for scripting |`bash`, `expect`
+mktar |Archive utility |`bash`, `age`\*
+mktar-batch |Archive utility for scripting |`bash`, `age`\*
rmtar |Delete 'tar' archive files |
rmzip |Delete 'zip' archive files |
-tarcat |Print contents of `tar` archive file(s) |
-tarls |List files within `tar` archive file(s) |
-untar |Wrapper around `tar` for easier decompression |
+tarcat |Unarchive utility for scripting |`bash`, `age`\*
+tarls |List files within archive files |`bash`, `age`\*
+untar |Unarchive utility |`bash`, `age`\*
zipls |List files within `zip` archive file(s) |`zipinfo`
*All* scripts support `-h` and `--help` for printing built-in documentation.
*All* scripts do nothing if no input arguments are given.
+\*These utilities use a fork of `age` that supports plaintext passphrases.
+See [git.dominic-ricottone.com/age.git].
+
+## Notes
+
+Per FreeBSD's `tar(1)`:
+
+> For maximum portability, scripts that invoke tar should use the bundled-
+> argument format above, should limit themselves to the c, t, and x modes,
+> and the b, f, m, v, and w options.
+
+I have noted that pretty much any viable implementation also supports `O` (extract to stdout).
+That includes BusyBox.
## To-Do
A archives/archive.bash => archives/archive.bash +273 -0
@@ 0,0 1,273 @@
+#!/bin/bash
+
+# See mktar-batch for simple usage
+
+archive() {
+ local tar_bin=/usr/bin/tar
+ local gpg_bin=/usr/bin/gpg
+ local age_bin=age
+
+ local encrypt=""
+ local encrypt_cmd=""
+ local encrypt_flags=""
+ local passphrase_flags=""
+ local passphrase=""
+ local archive_cmd=""
+ local archive_flags=""
+ local archive_late_flags=""
+ local archive_fn=""
+
+ local positional=()
+
+ while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ --archive=tar)
+ encrypt=0
+ encrypt_cmd=""
+ encrypt_flags=""
+ passphrase_flags=""
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cf"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.age)
+ encrypt=1
+ encrypt_cmd="${age_bin}"
+ encrypt_flags="${encrypt_flags} --encrypt --passphrase --output"
+ passphrase_flags="--plaintext"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}c"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gpg)
+ encrypt=1
+ encrypt_cmd="${gpg_bin}"
+ encrypt_flags="${encrypt_flags} --symmetric --output"
+ passphrase_flags="--batch --passphrase"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}c"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz)
+ encrypt=0
+ encrypt_cmd=""
+ encrypt_flags=""
+ passphrase_flags=""
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}czf"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz.age)
+ encrypt=1
+ encrypt_cmd="${age_bin}"
+ encrypt_flags="${encrypt_flags} --encrypt --passphrase --output"
+ passphrase_flags="--plaintext"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cz"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz.gpg)
+ encrypt=1
+ encrypt_cmd="${gpg_bin}"
+ encrypt_flags="${encrypt_flags} --symmetric --output"
+ passphrase_flags="--batch --passphrase"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cz"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz)
+ encrypt=0
+ encrypt_cmd=""
+ encrypt_flags=""
+ passphrase_flags=""
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cJf"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz.age)
+ encrypt=1
+ encrypt_cmd="${age_bin}"
+ encrypt_flags="${encrypt_flags} --encrypt --passphrase --output"
+ passphrase_flags="--plaintext"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cJ"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz.gpg)
+ encrypt=1
+ encrypt_cmd="${gpg_bin}"
+ encrypt_flags="${encrypt_flags} --symmetric --output"
+ passphrase_flags="--batch --passphrase"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cJ"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.zst)
+ encrypt=0
+ encrypt_cmd=""
+ encrypt_flags=""
+ passphrase_flags=""
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cf"
+ archive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.zst.age)
+ encrypt=1
+ encrypt_cmd="${age_bin}"
+ encrypt_flags="${encrypt_flags} --encrypt --passphrase --output"
+ passphrase_flags="--plaintext"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}c"
+ archive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.zst.gpg)
+ encrypt=1
+ encrypt_cmd="${gpg_bin}"
+ encrypt_flags="${encrypt_flags} --symmetric --output"
+ passphrase_flags="--batch --passphrase"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}c"
+ archive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.bz2)
+ encrypt=0
+ encrypt_cmd=""
+ encrypt_flags=""
+ passphrase_flags=""
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cjf"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.bz2.age)
+ encrypt=1
+ encrypt_cmd="${age_bin}"
+ encrypt_flags="${encrypt_flags} --encrypt --passphrase --output"
+ passphrase_flags="--plaintext"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cj"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.bz2.gpg)
+ encrypt=1
+ encrypt_cmd="${gpg_bin}"
+ encrypt_flags="${encrypt_flags} --symmetric --output"
+ passphrase_flags="--batch --passphrase"
+ archive_cmd="${tar_bin}"
+ archive_flags="${archive_flags}cj"
+ archive_late_flags=""
+ shift
+ ;;
+
+ --archive=*)
+ error_msg "unsupported archive type '${1}'"
+ ;;
+
+ --name)
+ archive_fn="$2"
+ shift; shift
+ ;;
+
+ --passphrase)
+ passphrase="$2"
+ shift; shift
+ ;;
+
+ *)
+ positional+=("$1")
+ shift
+ ;;
+ esac
+ done
+
+ # error if no input files given
+ if [[ "${#positional[@]}" -lt 1 ]]; then
+ error_msg "no input files given"
+ usage_msg
+ fi
+
+ # error if input file does not exist
+ for target in "${positional[@]}"; do
+ if [[ ! -f "$target" ]] && [[ ! -d "$target" ]]; then
+ error_msg "no such file '${target}'"
+ fi
+ done
+
+ # error if no archive file given
+ if [[ -z "$archive_fn" ]]; then
+ error_msg "no archive file given"
+ usage_msg
+ fi
+
+ # error if archive exists and should not be overwritten
+ if ! prompt_overwrite "$archive_fn"; then
+ error_msg "archive '${archive_fn}' cannot be overwritten"
+ usage_msg
+ fi
+
+ # error if archive is an input file
+ if contains "$archive_fn" "${positional[@]}"; then
+ error_msg "archive '${archive_fn}' cannot be an input file"
+ fi
+
+ # handle passphrase
+ if [[ ! -z "$passphrase_flags" && ! -z "$passphrase" ]]; then
+ passphrase_flags="${passphrase_flags} ${passphrase}"
+ else
+ passphrase_flags=
+ fi
+
+ # handle debugging information
+ local verbosity=/dev/stderr
+ if [[ "$verbose" -ne 1 ]]; then
+ verbosity=/dev/null
+ elif [[ "$encrypt" -eq 1 ]]; then
+ debug_msg "$archive_cmd $archive_flags $archive_late_flags ${positional[@]} 2>$verbosity | $encrypt_cmd $encrypt_flags $archive_fn $passphrase_flags 2>$verbosity"
+ else
+ debug_msg "$archive_cmd $archive_flags $archive_fn $archive_late_flags ${positional[@]} 2>$verbosity"
+ fi
+
+ # archive routine
+ if [[ "$encrypt" -eq 1 ]]; then
+ ( \
+ $archive_cmd $archive_flags $archive_late_flags "${positional[@]}" 2>$verbosity \
+ || error_msg "could not archive '${archive_fn}'" \
+ ) \
+ | ( \
+ $encrypt_cmd $encrypt_flags "$archive_fn" $passphrase_flags 2>$verbosity \
+ || error_msg "could not encrypt '${archive_fn}'" \
+ )
+ else
+ $archive_cmd $archive_flags "$archive_fn" $archive_late_flags "${positional[@]}" 2>$verbosity \
+ || error_msg "could not archive '${archive_fn}'"
+ fi
+}
+
M archives/mktar => archives/mktar +52 -303
@@ 1,74 1,34 @@
#!/bin/bash
name="mktar"
-version="1.3"
+version="1.4"
read -r -d '' help_message <<-EOF
Archive utility
- Usage: mktar [OPTIONS] INFILES
+ Usage: mktar -n OUTFILE [OPTIONS] INFILES
Options:
- -c, --compress compress archive with gzip
- --compress=ALGO compress archive with [none|gzip|xz|zstd|bzip2]
- -C, --checksum create checksum with SHA1
- --checksum=ALGO create checksum with [none|sha1|sha256]
- -e, --encrypt encrypt files with GPG
- --encrypt=ALGO encrypt files with [none|gpg|age]
- -h, --help print this message
- -n FILE, --name FILE name of backup file (Default: archive.tar)
- -q, --quiet suppress error messages and prompts
- -v, --verbose show additional messages
- -V, --version print version number and exit
+ --checksum=ALGO create checksum with [none|sha1|sha256]
+ -h, --help print this message
+ -n FILE, --name FILE name of archive
+ -p PASS, --passphrase PASS passphrase for encryption
+ -q, --quiet suppress error messages and prompts
+ -v, --verbose show additional messages
+ -V, --version print version number and exit
EOF
source /usr/local/lib/mylib.bash
+source /usr/local/lib/archive.bash
+archive_fn=""
+checksum=-1
positional=()
quiet=0
verbose=0
-compress=-1
-encrypt=-1
-checksum=-1
-archive_fn=""
while [[ $# -gt 0 ]]; do
case $1 in
- --compress=gz|--compress=gzip|--compress=1)
- debug_msg "Setting compress option to 1 (=gzip) (was ${compress})"
- compress=1
- shift
- ;;
-
- --compress=xz|--compress=2)
- debug_msg "Setting compress option to 2 (=xz) (was ${compress})"
- compress=2
- shift
- ;;
-
- --compress=zst|--compress=zstd|--compress=3)
- debug_msg "Setting compress option to 3 (=zstd) (was ${compress})"
- compress=3
- shift
- ;;
-
- --compress=bz2|--compress=bzip2|--compress=4)
- debug_msg "Setting compress option to 4 (=bzip2) (was ${compress})"
- compress=4
- shift
- ;;
-
- --compress=no|--compress=none|--compress=0)
- debug_msg "Setting compress option to 0 (=none) (was ${compress})"
- compress=0
- shift
- ;;
-
- --compress=*)
- attempted_compression="$(/usr/bin/printf "%s\n" "$1" | sed -e 's/^.*=//' )"
- error_msg "Unknown compression '${attempted_compression}'"
- ;;
-
- -c|--compress)
- debug_msg "Setting compress option to 1 (=gzip) (was ${compress})"
- compress=1
+ --checksum=no|--checksum=none|--checksum=0)
+ debug_msg "Setting checksum option to 0 (=none) (was ${checksum})"
+ checksum=0
shift
;;
@@ 84,52 44,11 @@ while [[ $# -gt 0 ]]; do
shift
;;
- --checksum=no|--checksum=none|--checksum=0)
- debug_msg "Setting checksum option to 0 (=none) (was ${checksum})"
- checksum=0
- shift
- ;;
-
--checksum=*)
attempted_checksum="$(/usr/bin/printf "%s\n" "$1" | sed -e 's/^.*=//' )"
error_msg "Unknown checksum '${attempted_checksum}'"
;;
- -C|--checksum)
- debug_msg "Setting checksum option to 1 (=SHA1) (was ${checksum})"
- checksum=1
- shift
- ;;
-
- --encrypt=gpg|--encrypt=1)
- debug_msg "Setting encrypt option to 1 (=GPG) (was ${encrypt})"
- encrypt=1
- shift
- ;;
-
- --encrypt=age|--encrypt=2)
- debug_msg "Setting encrypt option to 2 (=Age) (was ${encrypt})"
- encrypt=2
- shift
- ;;
-
- --encrypt=no|--encrypt=none|--encrypt=0)
- debug_msg "Setting encrypt option to 0 (=none) (was ${encrypt})"
- encrypt=0
- shift
- ;;
-
- --encrypt=*)
- attempted_encryption="$(/usr/bin/printf "%s\n" "$1" | sed -e 's/^.*=//' )"
- error_msg "Unknown encryption '${attempted_encryption}'"
- ;;
-
- -e|--encrypt)
- debug_msg "Setting encrypt option to 1 (=GPG) (was ${encrypt})"
- encrypt=1
- shift
- ;;
-
-h|--help)
help_msg
shift
@@ 141,6 60,12 @@ while [[ $# -gt 0 ]]; do
shift; shift
;;
+ -p|--passphrase)
+ debug_msg "Setting passphrase to ${2} (was ${passphrase})"
+ passphrase="--passphrase $2"
+ shift; shift
+ ;;
+
-q|--quiet)
debug_msg "Setting quiet option to 1 (was ${quiet})"
quiet=1
@@ 165,233 90,57 @@ while [[ $# -gt 0 ]]; do
esac
done
-# error if no filenames given
-if [[ "${#positional[@]}" -lt 1 ]]; then
- debug_msg "No input filenames were given"
+# error if no archive file given
+if [[ -z "$archive_fn" ]]; then
+ error_msg "no archive file given"
usage_msg
fi
-# determine compress action
-if [[ "$compress" -eq 1 ]]; then
- archive_action="tar.gz"
-elif [[ "$compress" -eq 2 ]]; then
- archive_action="tar.xz"
-elif [[ "$compress" -eq 3 ]]; then
- archive_action="tar.zst"
-elif [[ "$compress" -eq 4 ]]; then
- archive_action="tar.bz2"
-elif [[ "$compress" -eq -1 ]]; then
- debug_msg "No explicit compress option; parsing archive name..."
- case "$archive_fn" in
- *.tar)
- debug_msg "Detected tarball (no compress)"
- archive_action="tar"
- ;;
-
- *.tar.gz)
- debug_msg "Detected gzip compress"
- archive_action="tar.gz"
- ;;
-
- *.tar.xz)
- debug_msg "Detected xz compress"
- archive_action="tar.xz"
- ;;
-
- *.tar.zst)
- debug_msg "Detected zstandard compress"
- archive_action="tar.zst"
- ;;
-
- *.tar.bz2)
- debug_msg "Detected bz2 compress"
- archive_action="tar.bz2"
- ;;
-
- *)
- debug_msg "Could not parse archive name; defaulting to no compress"
- archive_action="tar"
- ;;
- esac
-else
- archive_action="tar"
-fi
-
-# determine encrypt action
-if [[ "$encrypt" -eq 1 ]]; then
- archive_action="${archive_action}.gpg"
-elif [[ "$encrypt" -eq 2 ]]; then
- archive_action="${archive_action}.age"
-elif [[ "$encrypt" -eq -1 ]]; then
- debug_msg "No explicit encrypt option; parsing archive name..."
- case "$archive_fn" in
- *.gpg)
- debug_msg "Detected gpg encrypt"
- archive_action="${archive_action}.gpg"
- ;;
-
- *.age)
- debug_msg "Detected age encrypt"
- archive_action="${archive_action}.age"
- ;;
+# determine archive action
+archive_action="$(archive_extension "$archive_fn" | tee >(>&2 /usr/bin/head -n -1) | /usr/bin/tail -n 1)"
- *)
- debug_msg "No explicit encrypt option and could not parse archive name; defaulting to no encrypt"
- archive_action="${archive_action}"
- ;;
- esac
-else
- archive_action="${archive_action}"
-fi
-
-# determine checksum action
+# determine checksum action and filename
if [[ "$checksum" -eq 1 ]]; then
checksum_action="sha1"
elif [[ "$checksum" -eq 2 ]]; then
checksum_action="sha256"
fi
+checksum_fn="$(fn_basename "$archive_fn").${checksum_action}"
-# output filename
-if [[ -z "$archive_fn" ]]; then
- archive_fn="archive.${archive_action}"
- checksum_fn="archive.${checksum_action}"
- debug_msg "No output filename was given, defaulting to '${archive_fn}'"
-else
- checksum_fn="$(fn_basename "$archive_fn").${checksum_action}"
+# check checksum files
+if [[ "$checksum" -ge 1 ]]; then
+ if contains "$checksum_fn" "${positional[@]}"; then
+ error_msg "checksum '${checksum_fn}' cannot be an input file"
+ elif ! prompt_overwrite "checksum_fn"; then
+ error_msg "checksum '${checksum_fn}' cannot be overwritten"
+ fi
fi
-# check files
-if contains "$archive_fn" "${positional[@]}"; then
- error_msg "Output file cannot also be input file ('${archive_fn}')"
-elif [[ "$checksum" -ge 1 ]] && contains "$checksum_fn" "${positional[@]}"; then
- error_msg "Output file cannot also be input file ('${checksum_fn}')"
+# check passphrase
+if [[ "$encrypt" -ge 1 && -z "$passphrase" ]]; then
+ passphrase=
fi
-if ! prompt_overwrite "$archive_fn"; then
- exit 1
-elif [[ "$checksum" -ge 1 ]] && ! prompt_overwrite "$checksum_fn"; then
+
+if ! archive --archive=$archive_action --name "$archive_fn" $passphrase "${positional[@]}"; then
exit 1
fi
-for target in "${positional[@]}"; do
- if [[ ! -f "$target" ]] && [[ ! -d "$target" ]]; then
- error_msg "No such file '${target}'"
- fi
-done
-# main routine
code=0
-case "$archive_action" in
-tar)
- if ! /usr/bin/tar -cf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.gpg)
- if ! /usr/bin/tar -c "${positional[@]}" | /usr/bin/gpg --symmetric --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.age)
- if ! /usr/bin/tar -c "${positional[@]}" | /usr/bin/age --encrypt --passphrase --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.gz)
- if ! /usr/bin/tar -czf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.gz.gpg)
- if ! /usr/bin/tar -cz "${positional[@]}" | /usr/bin/gpg --symmetric --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.gz.age)
- if ! /usr/bin/tar -cz "${positional[@]}" | /usr/bin/age --encrypt --passphrase --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.xz)
- if ! /usr/bin/tar -cJf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.xz.gpg)
- if ! /usr/bin/tar -cJ "${positional[@]}" | /usr/bin/gpg --symmetric --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.xz.age)
- if ! /usr/bin/tar -cJ "${positional[@]}" | /usr/bin/age --encrypt --passphrase --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.zst)
- if ! /usr/bin/tar --zstd -cf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.zst.gpg)
- if ! /usr/bin/tar --zstd -c "${positional[@]}" | /usr/bin/gpg --symmetric --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.zst.age)
- if ! /usr/bin/tar --zstd -c "${positional[@]}" | /usr/bin/age --encrypt --passphrase --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.bz2)
- if ! /usr/bin/tar -cjf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.bz2.gpg)
- if ! /usr/bin/tar -cj "${positional[@]}" | /usr/bin/gpg --symmetric --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.bz2.age)
- if ! /usr/bin/tar -cj "${positional[@]}" | /usr/bin/age --encrypt --passphrase --output "$archive_fn"; then
- code=1
- fi
- ;;
-esac
-
-# checksum routine
if [[ "$checksum" -ge 1 ]]; then
- if [[ -f "$archive_fn" ]]; then
- case "$checksum_action" in
- sha1)
- if ! /usr/bin/sha1sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
- code=1
- fi
- ;;
+ case "$checksum_action" in
+ sha1)
+ if ! /usr/bin/sha1sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
+ code=1
+ fi
+ ;;
- sha256)
- if ! /usr/bin/sha256sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
- code=1
- fi
- ;;
- esac
- else
- error_msg "No such file '${archive_fn}'"
- fi
+ sha256)
+ if ! /usr/bin/sha256sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
+ code=1
+ fi
+ ;;
+ esac
fi
-# return stored code
exit "$code"
M archives/mktar-batch => archives/mktar-batch +32 -195
@@ 1,7 1,7 @@
#!/bin/bash
name="mktar-batch"
-version="1.0"
+version="1.1"
read -r -d '' help_message <<-EOF
Archive utility for scripting
Usage: mktar-batch [--compress=ALGO] [--encrypt=ALSO --passphrase PASSWD] [--checksum=ALGO] [--name OUTFILE] INFILES
@@ 17,14 17,15 @@ read -r -d '' help_message <<-EOF
EOF
source /usr/local/lib/mylib.bash
+source /usr/local/lib/archive.bash
-positional=()
-verbose=0
+archive_fn=""
+checksum=-1
compress=-1
encrypt=-1
-checksum=-1
-archive_fn=""
passphrase=""
+positional=()
+verbose=0
while [[ $# -gt 0 ]]; do
case $1 in
@@ 105,7 106,7 @@ while [[ $# -gt 0 ]]; do
;;
--encrypt=*)
- attempted_encryption="$(/usr/bin/printf "%s\n" "$1" | sed -e 's/^.*=//' )"
+ attempted_encryption="$(/usr/bin/sed -e 's/^.*=//' <<<"$1")"
error_msg "Bad encrypt option '${attempted_encryption}'"
;;
@@ 142,13 143,6 @@ while [[ $# -gt 0 ]]; do
esac
done
-# error if no input or output filenames given
-if [[ "${#positional[@]}" -lt 1 ]]; then
- error_msg "No input filenames given"
-elif [[ -z "$archive_fn" ]]; then
- error_msg "No output filename given"
-fi
-
# construct archive action
if [[ "$compress" -eq 1 ]]; then
archive_action="tar.gz"
@@ 177,197 171,40 @@ fi
# construct checksum filename
checksum_fn="$(fn_basename "$archive_fn").${checksum_action}"
-# check files
-if contains "$archive_fn" "${positional[@]}"; then
- error_msg "Output file cannot also be input file ('${archive_fn}')"
-elif [[ "$checksum" -ge 1 ]] && contains "$checksum_fn" "${positional[@]}"; then
- error_msg "Output file cannot also be input file ('${checksum_fn}')"
-elif [[ -f "$archive_fn" ]]; then
- error_msg "Output file already exists ('${archive_fn}')"
-elif [[ "$checksum" -ge 1 && -f "$checksum_fn" ]]; then
- error_msg "Output file already exists ('${checksum_fn}')"
-fi
-for target in "${positional[@]}"; do
- if [[ ! -f "$target" ]] && [[ ! -d "$target" ]]; then
- error_msg "No such file '${target}'"
+# check checksum files
+if [[ "$checksum" -ge 1 ]]; then
+ if contains "$checksum_fn" "${positional[@]}"; then
+ error_msg "checksum '${checksum_fn}' cannot be an input file"
+ elif ! prompt_overwrite "checksum_fn"; then
+ error_msg "checksum '${checksum_fn}' cannot be overwritten"
fi
-done
+fi
# check passphrase
-if [[ "$checksum" -ge 1 && -z "$passphrase" ]]; then
+if [[ "$encrypt" -ge 1 && -z "$passphrase" ]]; then
error_msg "No passphrase given"
fi
-# main routine
-code=0
-case "$archive_action" in
-tar)
- if ! /usr/bin/tar -cf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.gpg)
- if ! /usr/bin/tar -c "${positional[@]}" | /usr/bin/gpg --symmetric --batch --passphrase "$passphrase" --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.age)
- /usr/bin/expect <<EOF
-spawn sh -c "/usr/bin/tar -c \"${positional[@]}\" | /usr/bin/age --encrypt --passphrase --output \"$archive_fn\""
-expect "*:"
-send "$passphrase\r"
-expect "*:"
-send "$passphrase\r"
-expect eof
-
-foreach {pid spawnid os_error_flag value} [wait] break
-exit $value
-EOF
- if [[ $? -ne 0 ]]; then
- code=1
- fi
- ;;
-
-tar.gz)
- if ! /usr/bin/tar -czf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.gz.gpg)
- if ! /usr/bin/tar -cz "${positional[@]}" | /usr/bin/gpg --symmetric --batch --passphrase "$passphrase" --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.gz.age)
- /usr/bin/expect <<EOF
-spawn sh -c "/usr/bin/tar -cz \"${positional[@]}\" | /usr/bin/age --encrypt --passphrase --output \"$archive_fn\""
-expect "*:"
-send "$passphrase\r"
-expect "*:"
-send "$passphrase\r"
-expect eof
-
-foreach {pid spawnid os_error_flag value} [wait] break
-exit $value
-EOF
- if [[ $? -ne 0 ]]; then
- code=1
- fi
- ;;
-
-tar.xz)
- if ! /usr/bin/tar -cJf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.xz.gpg)
- if ! /usr/bin/tar -cJ "${positional[@]}" | /usr/bin/gpg --symmetric --batch --passphrase "$passphrase" --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.xz.age)
- /usr/bin/expect <<EOF
-spawn sh -c "/usr/bin/tar -cJ \"${positional[@]}\" | /usr/bin/age --encrypt --passphrase --output \"$archive_fn\""
-expect "*:"
-send "$passphrase\r"
-expect "*:"
-send "$passphrase\r"
-expect eof
-
-foreach {pid spawnid os_error_flag value} [wait] break
-exit $value
-EOF
- if [[ $? -ne 0 ]]; then
- code=1
- fi
- ;;
-
-tar.zst)
- if ! /usr/bin/tar --zstd -cf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.zst.gpg)
- if ! /usr/bin/tar --zstd -c "${positional[@]}" | /usr/bin/gpg --symmetric --batch --passphrase "$passphrase" --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.zst.age)
- /usr/bin/expect <<EOF
-spawn sh -c "/usr/bin/tar --zstd -c \"${positional[@]}\" | /usr/bin/age --encrypt --passphrase --output \"$archive_fn\""
-expect "*:"
-send "$passphrase\r"
-expect "*:"
-send "$passphrase\r"
-expect eof
-
-foreach {pid spawnid os_error_flag value} [wait] break
-exit $value
-EOF
- if [[ $? -ne 0 ]]; then
- code=1
- fi
- ;;
-
-tar.bz2)
- if ! /usr/bin/tar -cjf "$archive_fn" "${positional[@]}"; then
- code=1
- fi
- ;;
-
-tar.bz2.gpg)
- if ! /usr/bin/tar -cj "${positional[@]}" | /usr/bin/gpg --symmetric --batch --passphrase "$passphrase" --output "$archive_fn"; then
- code=1
- fi
- ;;
-
-tar.bz2.age)
- /usr/bin/expect <<EOF
-spawn sh -c "/usr/bin/tar -cj \"${positional[@]}\" | /usr/bin/age --encrypt --passphrase --output \"$archive_fn\""
-expect "*:"
-send "$passphrase\r"
-expect "*:"
-send "$passphrase\r"
-expect eof
-
-foreach {pid spawnid os_error_flag value} [wait] break
-exit $value
-EOF
- if [[ $? -ne 0 ]]; then
- code=1
- fi
- ;;
-esac
+if ! archive --archive=$archive_action --name "$archive_fn" --passphrase "$passphrase" "${positional[@]}"; then
+ exit 1
+fi
-# checksum routine
+code=0
if [[ "$checksum" -ge 1 ]]; then
- if [[ -f "$archive_fn" ]]; then
- case "$checksum_action" in
- sha1)
- if ! /usr/bin/sha1sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
- code=1
- fi
- ;;
-
- sha256)
- if ! /usr/bin/sha256sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
- code=1
- fi
- ;;
- esac
- else
- error_msg "No such file '${archive_fn}'"
- fi
+ case "$checksum_action" in
+ sha1)
+ if ! /usr/bin/sha1sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
+ code=1
+ fi
+ ;;
+
+ sha256)
+ if ! /usr/bin/sha256sum "$archive_fn" | /usr/bin/awk '{print $1}' > "$checksum_fn"; then
+ code=1
+ fi
+ ;;
+ esac
fi
-# return stored code
exit "$code"
M archives/tarcat => archives/tarcat +53 -111
@@ 1,125 1,67 @@
-#!/bin/sh
+#!/bin/bash
name="tarcat"
-version="1.1"
+version="1.2"
help_message=$(/usr/bin/cat <<-EOF
- Print contents of target archive file(s)
+ Unarchive utility for scripting
Usage: tarcat [TARGET ..] [OPTIONS]
Options:
- -h, --help print this message and exit
- -q, --quiet suppress error messages
- -v, --version print version number and exit
+ -h, --help print this message and exit
+ -p PASS, --passphrase PASS passphrase for decryption
+ -q, --quiet suppress error messages
+ -v, --version print version number and exit
EOF
)
-. /usr/local/lib/myminiparse.sh
+source /usr/local/lib/mylib.bash
+source /usr/local/lib/unarchive.bash
+
+quiet=0
+passphrase=""
+positional=()
+verbose=0
+while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ -p|--passphrase)
+ passphrase="--passphrase $2"
+ shift; shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
code=0
-
-for target; do
- if [ ! -f "$target" ]; then
- if [ "$quiet" -eq 0 ]; then
- (>&2 /usr/bin/printf "%s: No such file '%s'\n" "$name" "$target")
- fi
+for archive_fn in "${positional[@]}"; do
+ archive_action="$(archive_extension "$archive_fn" | tee >(>&2 /usr/bin/head -n -1) | /usr/bin/tail -n 1)"
+ if ! unarchive --archive=$archive_action --stdout "$archive_fn" $passphrase; then
code=1
- else
- case "$target" in
- *.tar)
- if ! /usr/bin/tar -xOf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xO; then
- code=1
- fi
- ;;
-
- *.tar.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xO; then
- code=1
- fi
- ;;
-
- *.tar.gz)
- if ! /usr/bin/tar -xzOf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xzO; then
- code=1
- fi
- ;;
-
- *.tar.gz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xzO; then
- code=1
- fi
- ;;
-
- *.tar.xz)
- if ! /usr/bin/tar -xJOf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.xz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xJO; then
- code=1
- fi
- ;;
-
- *.tar.xz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xJO; then
- code=1
- fi
- ;;
-
- *.tar.zst|*.tar.zstd)
- if ! /usr/bin/tar --zstd -xOf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.zst.gpg|*.tar.zstd.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar --zstd -xO; then
- code=1
- fi
- ;;
-
- *.tar.zst.age|*.tar.zstd.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar --zstd -xO; then
- code=1
- fi
- ;;
-
- *.tar.bz2)
- if ! /usr/bin/tar -xjOf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.bz2.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xjO; then
- code=1
- fi
- ;;
-
- *.tar.bz2.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xjO; then
- code=1
- fi
- ;;
-
- *)
- if ! /usr/bin/tar -xOf "$target"; then
- code=1
- fi
- ;;
- esac
fi
done
M archives/tarls => archives/tarls +53 -119
@@ 1,133 1,67 @@
-#!/bin/sh
+#!/bin/bash
name="tarls"
-version="1.1"
+version="1.2"
help_message=$(/usr/bin/cat <<-EOF
- List files within 'tar' archive file(s)
+ List files within archive files
Usage: tarls TARGET [..] [OPTIONS]
Options:
- -h, --help print this message and exit
- -q, --quiet suppress error messages
- -v, --version print version number and exit
+ -h, --help print this message and exit
+ -p PASS, --passphrase PASS passphrase for decryption
+ -q, --quiet suppress error messages
+ -v, --version print version number and exit
EOF
)
-. /usr/local/lib/myminiparse.sh
-
-# error if no directory names given
-if [ "$#" -eq 0 ]; then
- (>&2 /usr/bin/printf "Usage: tarls TARGET [OPTIONS]\n")
- exit 1
-elif [ "$#" -eq 1 ] && [ "$quiet" -eq 1 ]; then
- exit 1
-fi
+source /usr/local/lib/mylib.bash
+source /usr/local/lib/unarchive.bash
+
+quiet=0
+passphrase=""
+positional=()
+verbose=0
+while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ -p|--passphrase)
+ passphrase="--passphrase $2"
+ shift; shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
-# main routine
code=0
-for target; do
- if [ ! -f "$target" ]; then
- if [ "$quiet" -eq 0 ]; then
- (>&2 /usr/bin/printf "%s: No such file '%s'\n" "$name" "$target")
- fi
+for archive_fn in "${positional[@]}"; do
+ archive_action="$(archive_extension "$archive_fn" | tee >(>&2 /usr/bin/head -n -1) | /usr/bin/tail -n 1)"
+ if ! unarchive --archive=$archive_action --list "$archive_fn" $passphrase; then
code=1
- else
- case "$target" in
- *.tar)
- if ! /usr/bin/tar -tf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -t; then
- code=1
- fi
- ;;
-
- *.tar.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -t; then
- code=1
- fi
- ;;
-
- *.tar.gz)
- if ! /usr/bin/tar -tzf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -tz; then
- code=1
- fi
- ;;
-
- *.tar.gz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -tz; then
- code=1
- fi
- ;;
-
- *.tar.xz)
- if ! /usr/bin/tar -tJf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.xz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -tJ; then
- code=1
- fi
- ;;
-
- *.tar.xz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -tJ; then
- code=1
- fi
- ;;
-
- *.tar.zst|*.tar.zstd)
- if ! /usr/bin/tar --zstd -tf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.zst.gpg|*.tar.zstd.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar --zstd -t; then
- code=1
- fi
- ;;
-
- *.tar.zst.age|*.tar.zstd.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar --zstd -t; then
- code=1
- fi
- ;;
-
- *.tar.bz2)
- if ! /usr/bin/tar -tjf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.bz2.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -tj; then
- code=1
- fi
- ;;
-
- *.tar.bz2.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -tj; then
- code=1
- fi
- ;;
-
- *)
- if ! /usr/bin/tar -tf "$target"; then
- code=1
- fi
- ;;
- esac
fi
done
M archives/test_mktar_tarcat.sh => archives/test_mktar_tarcat.sh +44 -17
@@ 11,22 11,32 @@ test_compression() {
NONE)
arg_compression="none"
fn_compressed="archive.tar"
+ fn_compressed_gpg="archive.tar.gpg"
+ fn_compressed_age="archive.tar.age"
;;
GZIP)
arg_compression="gzip"
fn_compressed="archive.tar.gz"
+ fn_compressed_gpg="archive.tar.gz.gpg"
+ fn_compressed_age="archive.tar.gz.age"
;;
XZ)
arg_compression="xz"
fn_compressed="archive.tar.xz"
+ fn_compressed_gpg="archive.tar.xz.gpg"
+ fn_compressed_age="archive.tar.xz.age"
;;
ZSTD)
arg_compression="zstd"
fn_compressed="archive.tar.zst"
+ fn_compressed_gpg="archive.tar.zst.gpg"
+ fn_compressed_age="archive.tar.zst.age"
;;
BZIP2)
arg_compression="bzip2"
fn_compressed="archive.tar.bz2"
+ fn_compressed_gpg="archive.tar.bz2.gpg"
+ fn_compressed_age="archive.tar.bz2.age"
;;
*)
printf "Failure in compression tests: not a valid scheme: '%s'\n" "$1"
@@ 34,50 44,67 @@ test_compression() {
;;
esac
- # try basic compression
- ../mktar --compress="$arg_compression" compression_target.txt
+ #
+ # mktar tests
+ #
+
+ test="implicit compression with short name flag using"
+ ../mktar -n "$fn_compressed" compression_target.txt
../tarcat "$fn_compressed" > compression_result.txt
if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
- printf "Failure in compression tests: basic compression: '%s'\n" "$1"
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
exit 1
fi
rm -f compression_result.txt "$fn_compressed"
- # try basic compression with misordered positional arguments
- ../mktar compression_target.txt --compress="$arg_compression"
+ test="implicit compression with long name flag using"
+ ../mktar --name "$fn_compressed" compression_target.txt
../tarcat "$fn_compressed" > compression_result.txt
if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
- printf "Failure in compression tests: basic compression with misordered positional arguments: '%s'\n" "$1"
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
exit 1
fi
rm -f compression_result.txt "$fn_compressed"
- # try implicit compression with short name flag
- ../mktar -n "$fn_compressed" compression_target.txt
+ #
+ # mktar-batch tests
+ #
+
+ test="compression using"
+ ../mktar-batch --compress="$arg_compression" --name "$fn_compressed" compression_target.txt
../tarcat "$fn_compressed" > compression_result.txt
if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
- printf "Failure in compression tests: implicit compression with short name flag: '%s'\n" "$1"
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
exit 1
fi
rm -f compression_result.txt "$fn_compressed"
- # try implicit compression with long name flag
- ../mktar --name "$fn_compressed" compression_target.txt
+ test="compression with misordered positional arguments using"
+ ../mktar-batch compression_target.txt --compress="$arg_compression" --name "$fn_compressed"
../tarcat "$fn_compressed" > compression_result.txt
if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
- printf "Failure in compression tests: implicit compression with long name flag: '%s'\n" "$1"
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
exit 1
fi
rm -f compression_result.txt "$fn_compressed"
- # try batch compression
- ../mktar-batch --compress="$arg_compression" --name "$fn_compressed" compression_target.txt
- ../tarcat "$fn_compressed" > compression_result.txt
+ test="compression using gpg and"
+ ../mktar-batch --compress="$arg_compression" --encrypt="gpg" --passphrase test123 --name "$fn_compressed_gpg" compression_target.txt
+ ../tarcat --passphrase test123 "$fn_compressed_gpg" > compression_result.txt
if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
- printf "Failure in compression tests: basic compression: '%s'\n" "$1"
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
exit 1
fi
- rm -f compression_result.txt "$fn_compressed"
+ rm -f compression_result.txt "$fn_compressed_gpg"
+
+ test="compression using age and"
+ ../mktar-batch --compress="$arg_compression" --encrypt="age" --passphrase test123 --name "$fn_compressed_age" compression_target.txt
+ ../tarcat --passphrase test123 "$fn_compressed_age" > compression_result.txt
+ if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
+ printf "Failure in compression tests: %s '%s'\n" "$test" "$1"
+ exit 1
+ fi
+ rm -f compression_result.txt "$fn_compressed_age"
}
test_compression NONE
A archives/unarchive.bash => archives/unarchive.bash +251 -0
@@ 0,0 1,251 @@
+#!/bin/bash
+
+# See tarcat for simple usage
+
+unarchive() {
+ local tar_bin=/usr/bin/tar
+ local gpg_bin=/usr/bin/gpg
+ local age_bin=age
+
+ local decrypt=""
+ local decrypt_cmd=""
+ local decrypt_flags=""
+ local passphrase_flags=""
+ local passphrase=""
+ local unarchive_cmd=""
+ local unarchive_flags=""
+ local unarchive_late_flags=""
+
+ while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ --archive=tar)
+ decrypt=0
+ decrypt_cmd=""
+ decrypt_flags=""
+ passphrase_flags=""
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xf"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.age)
+ decrypt=1
+ decrypt_cmd="${age_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt"
+ passphrase_flags="--plaintext"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}x"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gpg)
+ decrypt=1
+ decrypt_cmd="${gpg_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt --quiet"
+ passphrase_flags="--batch --passphrase"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}x"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz)
+ decrypt=0
+ decrypt_cmd=""
+ decrypt_flags=""
+ passphrase_flags=""
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xzf"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz.age)
+ decrypt=1
+ decrypt_cmd="${age_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt"
+ passphrase_flags="--plaintext"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xz"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.gz.gpg)
+ decrypt=1
+ decrypt_cmd="${gpg_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt --quiet"
+ passphrase_flags="--batch --passphrase"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xz"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz)
+ decrypt=0
+ decrypt_cmd=""
+ decrypt_flags=""
+ passphrase_flags=""
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xJf"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz.age)
+ decrypt=1
+ decrypt_cmd="${age_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt"
+ passphrase_flags="--plaintext"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xJ"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.xz.gpg)
+ decrypt=1
+ decrypt_cmd="${gpg_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt --quiet"
+ passphrase_flags="--batch --passphrase"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xJ"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.zst)
+ decrypt=0
+ decrypt_cmd=""
+ decrypt_flags=""
+ passphrase_flags=""
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xf"
+ unarchive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.zst.age)
+ decrypt=1
+ decrypt_cmd="${age_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt"
+ passphrase_flags="--plaintext"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}x"
+ unarchive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.zst.gpg)
+ decrypt=1
+ decrypt_cmd="${gpg_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt --quiet"
+ passphrase_flags="--batch --passphrase"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}x"
+ unarchive_late_flags="--zstd"
+ shift
+ ;;
+
+ --archive=tar.bz2)
+ decrypt=0
+ decrypt_cmd=""
+ decrypt_flags=""
+ passphrase_flags=""
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xjf"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.bz2.age)
+ decrypt=1
+ decrypt_cmd="${age_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt"
+ passphrase_flags="--plaintext"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xj"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=tar.bz2.gpg)
+ decrypt=1
+ decrypt_cmd="${gpg_bin}"
+ decrypt_flags="${decrypt_flags} --decrypt --quiet"
+ passphrase_flags="--batch --passphrase"
+ unarchive_cmd="${tar_bin}"
+ unarchive_flags="${unarchive_flags}xj"
+ unarchive_late_flags=""
+ shift
+ ;;
+
+ --archive=*)
+ error_msg "unsupported archive type '${1}'"
+ ;;
+
+ --list)
+ unarchive_flags="$(/usr/bin/sed -e 's/x/t/' <<<"$unarchive_flags")"
+ shift
+ ;;
+
+ --passphrase)
+ passphrase="$2"
+ shift; shift
+ ;;
+
+ --stdout)
+ unarchive_flags="O${unarchive_flags}"
+ shift
+ ;;
+
+ *)
+ archive_fn="$1"
+ shift
+ ;;
+ esac
+ done
+
+ # error if archive does not exist
+ if [[ ! -f "$archive_fn" ]]; then
+ error_msg "no such archive '${archive_fn}'"
+ usage_msg
+ fi
+
+ # handle passphrase
+ if [[ ! -z "$passphrase_flags" && ! -z "$passphrase" ]]; then
+ passphrase_flags="${passphrase_flags} ${passphrase}"
+ else
+ passphrase_flags=
+ fi
+
+ # handle debugging information
+ local verbosity=/dev/stderr
+ if [[ "$verbose" -ne 1 ]]; then
+ verbosity=/dev/null
+ elif [[ "$decrypt" -eq 1 ]]; then
+ debug_msg "$decrypt_cmd $decrypt_flags $archive_fn $passphrase_flags 2>$verbosity | $unarchive_cmd $unarchive_flags $unarchive_late_flags 2>$verbosity"
+ else
+ debug_msg "$unarchive_cmd $unarchive_flags $archive_fn $unarchive_late_flags 2>$verbosity"
+ fi
+
+ # unarchive routine
+ if [[ "$decrypt" -eq 1 ]]; then
+ ( \
+ $decrypt_cmd $decrypt_flags $passphrase_flags "$archive_fn" 2>$verbosity \
+ || error_msg "could not decrypt '${archive_fn}'" \
+ ) \
+ | ( \
+ $unarchive_cmd $unarchive_flags $unarchive_late_flags 2>$verbosity \
+ || error_msg "could not unarchive '${archive_fn}'" \
+ )
+ else
+ $unarchive_cmd $unarchive_flags "$archive_fn" $unarchive_late_flags 2>$verbosity \
+ || error_msg "could not unarchive '${archive_fn}'"
+ fi
+}
+
M archives/untar => archives/untar +53 -119
@@ 1,133 1,67 @@
-#!/bin/sh
+#!/bin/bash
name="untar"
-version="1.1"
+version="1.2"
help_message=$(/usr/bin/cat <<-EOF
- Wrapper around 'tar' for easier decompression
+ Unarchive utility
Usage: untar TARGET [..] [OPTIONS]
Options:
- -h, --help print this message and exit
- -q, --quiet suppress error messages
- -v, --version print version number and exit
+ -h, --help print this message and exit
+ -p PASS, --passphrase PASS passphrase for decryption
+ -q, --quiet suppress error messages
+ -v, --version print version number and exit
EOF
)
-. /usr/local/lib/myminiparse.sh
-
-# error if no directory names given
-if [ "$#" -eq 0 ]; then
- (>&2 /usr/bin/printf "Usage: untar TARGET [OPTIONS]\n")
- exit 1
-elif [ "$#" -eq 1 ] && [ "$quiet" -eq 1 ]; then
- exit 1
-fi
+source /usr/local/lib/mylib.bash
+source /usr/local/lib/unarchive.bash
+
+quiet=0
+passphrase=""
+positional=()
+verbose=0
+while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ -p|--passphrase)
+ passphrase="--passphrase $2"
+ shift; shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
-# main routine
code=0
-for target; do
- if [ ! -f "$target" ]; then
- if [ "$quiet" -eq 0 ]; then
- (>&2 /usr/bin/printf "%s: No such file '%s'\n" "$name" "$target")
- fi
+for archive_fn in "${positional[@]}"; do
+ archive_action="$(archive_extension "$archive_fn" | tee >(>&2 /usr/bin/head -n -1) | /usr/bin/tail -n 1)"
+ if ! unarchive --archive=$archive_action "$archive_fn" $passphrase; then
code=1
- else
- case "$target" in
- *.tar)
- if ! /usr/bin/tar -xf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -x; then
- code=1
- fi
- ;;
-
- *.tar.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -x; then
- code=1
- fi
- ;;
-
- *.tar.gz)
- if ! /usr/bin/tar -xzf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.gz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xz; then
- code=1
- fi
- ;;
-
- *.tar.gz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xz; then
- code=1
- fi
- ;;
-
- *.tar.xz)
- if ! /usr/bin/tar -xJf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.xz.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xJ; then
- code=1
- fi
- ;;
-
- *.tar.xz.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xJ; then
- code=1
- fi
- ;;
-
- *.tar.zst|*.tar.zstd)
- if ! /usr/bin/tar --zstd -xf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.zst.gpg|*.tar.zstd.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar --zstd -x; then
- code=1
- fi
- ;;
-
- *.tar.zst.age|*.tar.zstd.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar --zstd -x; then
- code=1
- fi
- ;;
-
- *.tar.bz2)
- if ! /usr/bin/tar -xjf "$target"; then
- code=1
- fi
- ;;
-
- *.tar.bz2.gpg)
- if ! /usr/bin/gpg --decrypt "$target" | /usr/bin/tar -xj; then
- code=1
- fi
- ;;
-
- *.tar.bz2.age)
- if ! /usr/bin/age --decrypt "$target" | /usr/bin/tar -xj; then
- code=1
- fi
- ;;
-
- *)
- if ! /usr/bin/tar -xf "$target"; then
- code=1
- fi
- ;;
- esac
fi
done
M core/mylib.bash => core/mylib.bash +4 -1
@@ 264,6 264,9 @@ fn_extension() {
# filename matches a pattern -> pattern without leading .
# else ->
+# There is also debug output
+# Suggested usage:
+# archive_action="$(archive_extension "$archive_fn" | tee >(>&2 /usr/bin/head -n -1) | /usr/bin/tail -n 1)"
archive_extension() {
local ext=
@@ 348,6 351,6 @@ archive_extension() {
;;
esac
- /usr/bin/printf "%s\n" "$ext"
+ /usr/bin/printf '%s\n' "$ext"
}