Commit | Line | Data |
---|---|---|
dcd9d7e3 SBS |
1 | #!/usr/bin/env bash |
2 | # Desc: Rename files to remove common prefix | |
3 | # Usage: triml.sh [FILE] ([FILE]…) | |
4 | # Example: triml.sh ./*.txt | |
5 | # Version: 0.0.1 | |
6 | ||
7 | yell() { echo "$0: $*" >&2; } # print script path and all args to stderr | |
8 | die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status | |
9 | must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails | |
10 | get_prefix() { | |
11 | # Desc: Iteratively identify common prefix | |
12 | # Input: "$@" arguments | |
13 | # Output: stdout | |
14 | local prefix="$1"; # start with first arg | |
15 | shift; # don't compare first to first | |
16 | for arg in "$@"; do | |
17 | while [[ "$arg" != "$prefix"* ]]; do | |
18 | prefix="${prefix%?}"; # trim end of prefix if match | |
19 | done; | |
20 | done; | |
21 | printf "%s" "$prefix"; | |
22 | }; # Get common prefix of arguments | |
23 | show_usage() { | |
24 | # Desc: Display script usage information | |
25 | # Usage: show_usage | |
26 | # Version 0.0.2 | |
27 | # Input: none | |
28 | # Output: stdout | |
29 | # Depends: GNU-coreutils 8.30 (cat) | |
30 | cat <<'EOF' | |
31 | USAGE: | |
32 | triml.sh FILE [FILE…] | |
33 | ||
34 | OPTIONS: | |
35 | (none) | |
36 | ||
37 | EXAMPLE: | |
38 | triml.sh | |
39 | triml.sh ./*.txt | |
40 | EOF | |
41 | } # Display information on how to use this script. | |
42 | prompt_continue() { | |
43 | # Desc: Prompt user to go approve/disapprove or list files to be moved. | |
44 | while true; do | |
45 | read -rp "Rename ${#args[@]} files? (y/N or l/list): " choice; | |
46 | case "${choice,,}" in | |
47 | y|yes) | |
48 | yell "STATUS:Renaming..."; | |
49 | return 0; | |
50 | ;; | |
51 | l|list) | |
52 | for i in "${!args[@]}"; do | |
53 | yell "Rename: ${args[i]} -> ${args_defront[i]}"; | |
54 | done; | |
55 | ;; | |
56 | n|no) | |
57 | die "FATAL:Operation aborted."; | |
58 | ;; | |
59 | *) | |
60 | yell "Invalid option."; | |
61 | esac; | |
62 | done; | |
63 | }; # prompt user to continue operation | |
64 | main () { | |
65 | declare -a args args_defront; | |
66 | declare prefix; | |
67 | declare path_dir name_file name_file_new; | |
68 | ||
69 | # Check if no arguments are passed | |
70 | if [[ "$#" -le 0 ]]; then | |
71 | ## Act on working dir files | |
72 | mapfile -t args < <(find . -mindepth 1 -maxdepth 1 -type f); | |
73 | else | |
74 | ## Act on argument-specified file paths | |
75 | args=("$@"); | |
76 | fi; | |
77 | ||
78 | # Check that all args are file paths | |
79 | for arg in "${args[@]}"; do | |
80 | if [[ ! -f "$arg" ]]; then | |
81 | show_usage; | |
82 | die "FATAL:Not a file:${arg}"; fi; | |
83 | done; | |
84 | ||
85 | # Get common prefix of all file basenames | |
86 | ## Assemble directory paths and file name arrays | |
87 | for i in "${!args[@]}"; do | |
88 | #args_path[i]="$(dirname "${args[i]}")"; | |
89 | args_file[i]="$(basename "${args[i]}")"; | |
90 | done; | |
91 | prefix="$(get_prefix "${args_file[@]}")"; | |
92 | #declare -p args prefix; # debug | |
93 | if [[ "${#prefix}" -le 0 ]]; then | |
94 | #declare -p prefix; # debug | |
95 | die "FATAL:No file prefix found."; fi; | |
96 | ||
97 | # Assemble paths with defronted basenames | |
98 | for i in "${!args[@]}"; do | |
99 | path_dir="$(dirname "${args[i]}")"; | |
100 | name_file="$(basename "${args[i]}")"; | |
101 | name_file_new="${name_file#"${prefix}"}"; | |
102 | args_defront[i]="${path_dir}/${name_file_new}"; | |
103 | done; | |
104 | ||
105 | # Throw rename warning | |
106 | must prompt_continue; | |
107 | ||
108 | # Rename files to defront prefix | |
109 | for i in "${!args[@]}"; do | |
110 | if mv -n "${args[i]}" "${args_defront[i]}"; then | |
111 | yell "STATUS:Moved ${args[i]} to ${args_defront[i]}"; | |
112 | else | |
113 | die "FATAL:Failed to move ${args[i]} to ${args_defront[i]}"; | |
114 | fi; | |
115 | done; | |
116 | }; | |
117 | main "$@"; | |
118 | ||
119 | # Author: Steven Baltakatei Sandoval | |
120 | # License: GPLv3+ |