From: Steven Baltakatei Sandoval Date: Wed, 11 Sep 2024 04:30:33 +0000 (+0000) Subject: feat(user/triml.sh):Defronts shared filename prefixes X-Git-Url: https://zdv2.bktei.com/gitweb/BK-2020-03.git/commitdiff_plain/dcd9d7e32a746f882a2b46fb57c27e29dca9b932?ds=inline feat(user/triml.sh):Defronts shared filename prefixes --- diff --git a/user/triml.sh b/user/triml.sh new file mode 100755 index 0000000..45dbe4a --- /dev/null +++ b/user/triml.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash +# Desc: Rename files to remove common prefix +# Usage: triml.sh [FILE] ([FILE]…) +# Example: triml.sh ./*.txt +# Version: 0.0.1 + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +get_prefix() { + # Desc: Iteratively identify common prefix + # Input: "$@" arguments + # Output: stdout + local prefix="$1"; # start with first arg + shift; # don't compare first to first + for arg in "$@"; do + while [[ "$arg" != "$prefix"* ]]; do + prefix="${prefix%?}"; # trim end of prefix if match + done; + done; + printf "%s" "$prefix"; +}; # Get common prefix of arguments +show_usage() { + # Desc: Display script usage information + # Usage: show_usage + # Version 0.0.2 + # Input: none + # Output: stdout + # Depends: GNU-coreutils 8.30 (cat) + cat <<'EOF' + USAGE: + triml.sh FILE [FILE…] + + OPTIONS: + (none) + + EXAMPLE: + triml.sh + triml.sh ./*.txt +EOF +} # Display information on how to use this script. +prompt_continue() { + # Desc: Prompt user to go approve/disapprove or list files to be moved. + while true; do + read -rp "Rename ${#args[@]} files? (y/N or l/list): " choice; + case "${choice,,}" in + y|yes) + yell "STATUS:Renaming..."; + return 0; + ;; + l|list) + for i in "${!args[@]}"; do + yell "Rename: ${args[i]} -> ${args_defront[i]}"; + done; + ;; + n|no) + die "FATAL:Operation aborted."; + ;; + *) + yell "Invalid option."; + esac; + done; +}; # prompt user to continue operation +main () { + declare -a args args_defront; + declare prefix; + declare path_dir name_file name_file_new; + + # Check if no arguments are passed + if [[ "$#" -le 0 ]]; then + ## Act on working dir files + mapfile -t args < <(find . -mindepth 1 -maxdepth 1 -type f); + else + ## Act on argument-specified file paths + args=("$@"); + fi; + + # Check that all args are file paths + for arg in "${args[@]}"; do + if [[ ! -f "$arg" ]]; then + show_usage; + die "FATAL:Not a file:${arg}"; fi; + done; + + # Get common prefix of all file basenames + ## Assemble directory paths and file name arrays + for i in "${!args[@]}"; do + #args_path[i]="$(dirname "${args[i]}")"; + args_file[i]="$(basename "${args[i]}")"; + done; + prefix="$(get_prefix "${args_file[@]}")"; + #declare -p args prefix; # debug + if [[ "${#prefix}" -le 0 ]]; then + #declare -p prefix; # debug + die "FATAL:No file prefix found."; fi; + + # Assemble paths with defronted basenames + for i in "${!args[@]}"; do + path_dir="$(dirname "${args[i]}")"; + name_file="$(basename "${args[i]}")"; + name_file_new="${name_file#"${prefix}"}"; + args_defront[i]="${path_dir}/${name_file_new}"; + done; + + # Throw rename warning + must prompt_continue; + + # Rename files to defront prefix + for i in "${!args[@]}"; do + if mv -n "${args[i]}" "${args_defront[i]}"; then + yell "STATUS:Moved ${args[i]} to ${args_defront[i]}"; + else + die "FATAL:Failed to move ${args[i]} to ${args_defront[i]}"; + fi; + done; +}; +main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+