]> zdv2.bktei.com Git - BK-2020-03.git/blob - user/gthumb/prune.org
feat(unitproc/bkt-sum_float):Sums stdin floats
[BK-2020-03.git] / user / gthumb / prune.org
1 #+AUTHOR: Steven Baltakatei Sandoval
2 #+DATE: 2026-08-01
3 #+TITLE: gThumb prune
4
5 ** Summary
6 This work describes a way to quickly move groups of photograph files
7 (e.g. ~DSC00001.JPG~, ~DSC00001.ARW~, etc.) as well as associated
8 sidecar files into desired directories via keyboard shortcuts in
9 gThumb.
10
11 The method centers around a Bash script named ~gthumb-prune.sh~ which
12 may be bound to a gThumb keyboard shortcut to quickly move selected
13 image files to a desired location. The Bash script is run by a short
14 shell script specified in gThumbΚΌs πŸ”§ β†’ Personalize… menu.
15 Additionally, sidecar files as well as associated files sharing the
16 same file name stem (i.e. ~../*/DSC00001.*~) are also grouped and
17 moved to the desired location.
18
19 ** Stats
20 Version: 0.0.4
21 License: GPLv3+
22 gThumb version: ~3.12.6~
23
24 ** Usage
25 Let us say, that we have a set of photos in the following
26 locations:
27
28 #+begin_example
29 .
30 β”œβ”€β”€ ARW
31 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
32 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
33 β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
34 β”‚Β Β  β”œβ”€β”€ DSC00002.ARW.ots
35 β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
36 β”‚Β Β  └── DSC00003.ARW.ots
37 └── JPG
38 β”œβ”€β”€ DSC00001.JPG
39 β”œβ”€β”€ DSC00001.JPG.ots
40 β”œβ”€β”€ DSC00002.JPG
41 β”œβ”€β”€ DSC00002.JPG.ots
42 β”œβ”€β”€ DSC00002.JPG
43 └── DSC00002.JPG.ots
44 #+end_example
45
46 Let us say gThumb has the ~JPG~ directory open and we have selected
47 ~DSC00002.JPG~ which we want to keep. We also want to keep the
48 associated ~DSC00002.JPG.ots~ as well as the ~DSC00002.ARW~ and
49 ~DSC00002.ARW.ots~ files in the neighboring ~ARW~ directory. We wish
50 to discard all other photograph files.
51
52 First, we configure a ~keep~ shortcut. In the gThumbΚΌs πŸ”§ β†’
53 Personalize… menu, click the *New* button. Set the *Name* to
54 ~keep~. Set the *Command* to:
55
56 : fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" "keep" %F; fi;
57
58 Where ~$HOME/.local/bin/gthumb-prune.sh~ is the path for the Bash
59 script (see the ~Code~ section below).
60
61 Set the *Shortcut* to ~Shift+K~. Make sure the box β€œTerminal command
62 (shell script)” box is checked and the β€œExecute command once for every
63 file” is *not* checked. Click the *Save* button to close the ~Edit
64 Command~ window. Click the *Ok* button to close the ~Commands~ window.
65
66 Now, with ~DSC00002.JPG~ selected, press ~Shift+K~ on your
67 keyboard. The image should disappear from view and a new directory
68 should appear in the the left navbar, reflecting a new directory structure.
69
70 #+begin_example
71 .
72 β”œβ”€β”€ ARW
73 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
74 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
75 β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
76 β”‚Β Β  └── DSC00003.ARW.ots
77 β”œβ”€β”€ JPG
78 β”‚Β Β  β”œβ”€β”€ DSC00001.JPG
79 β”‚Β Β  β”œβ”€β”€ DSC00001.JPG.ots
80 β”‚Β Β  β”œβ”€β”€ DSC00003.JPG
81 β”‚Β Β  └── DSC00003.JPG.ots
82 └── keep
83 β”œβ”€β”€ ARW
84 β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
85 β”‚Β Β  └── DSC00002.ARW.ots
86 └── JPG
87 β”œβ”€β”€ DSC00002.JPG
88 └── DSC00002.JPG.ots
89 #+end_example
90
91 The ~DSC0002.*~ files (4 in total) have been moved to now reside
92 within a ~keep~ directory with their ~JPG~ and ~ARW~ subdirectory
93 structure preserved. Thus, the ~./JPG/~ and ~./ARW/~ directories have
94 been pruned.
95
96 If we want to trash the remaining ~DSC00001.*~ and ~DSC00003.*~ files,
97 we can create another shortcut to group and move files into a ~.trash~
98 directory next to ~keep~.
99
100 Repeat the procedure for creating a shortcut, but *Name* it ~rmall~
101 and set the *Command* to be:
102
103 : fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" ".trash" %F; fi;
104
105 Note the change from ~keep~ to ~.trash~. Set the keyboard *Shortcut*
106 to ~Shift+T~.
107
108 Now, with gThumb looking at the contents of ~./JPG~, and with
109 ~DSC00001.JPG~ and ~DSC00003.JPG~ selected, press ~Shift+T~. The two
110 images should disappear, leaving ~./JPG~ now empty. The navbar to the
111 left should not show any change since ~.trash~ is a dot directory and
112 so is normally hidden. Nonetheless, the directory structure has now
113 changed to:
114
115 #+begin_example
116 .
117 β”œβ”€β”€ ARW
118 β”œβ”€β”€ JPG
119 β”œβ”€β”€ keep
120 β”‚Β Β  β”œβ”€β”€ ARW
121 β”‚Β Β  β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
122 β”‚Β Β  β”‚Β Β  └── DSC00002.ARW.ots
123 β”‚Β Β  └── JPG
124 β”‚Β Β  β”œβ”€β”€ DSC00002.JPG
125 β”‚Β Β  └── DSC00002.JPG.ots
126 └── .trash
127 β”œβ”€β”€ ARW
128 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
129 β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
130 β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
131 β”‚Β Β  └── DSC00003.ARW.ots
132 └── JPG
133 β”œβ”€β”€ DSC00001.JPG
134 β”œβ”€β”€ DSC00001.JPG.ots
135 β”œβ”€β”€ DSC00003.JPG
136 └── DSC00003.JPG.ots
137 #+end_Example
138
139 So, the contents of ~./JPG/~ may be pruned by selecting files you want
140 to keep and pressing ~Shift+K~ and by selecting files you want to
141 trash and pressing ~Shift+T~. Then, if you are really sure about
142 deleting the undesired files, delete the contents of ~.trash~ via the
143 terminal command:
144
145 : $ rm -r ./.trash/*
146
147 ** Code
148 gthumb-prune.sh:
149
150 #+begin_code
151 #!/bin/bash
152 # Desc: Prunes files selected by gThumb.
153 # Note: Moves files into a directory with a specified name.
154 # Usage: gthumb-prune.sh [STR dirname] [FILES…]
155 # Example: $HOME/.local/bin/gthumb-prune.sh keep %F
156 # If '%F' expanded to `~/Pics/MyJPGs/DSC00001.JPG`, then
157 # "$HOME/Pics/*/DSC00001.*" files are moved to:
158 # '~/Pics/keep/MyJPGs/' .
159 #
160 # If '%F' expanded to multiple files, then the move
161 # operations to 'keep' are performed for each file.
162 # Input: arg1 str directory to send selected files
163 # arg2+ str path of selected file(s)
164 # Version: 0.0.4
165
166 fdebug=/tmp/gtPruneLog.txt;
167
168 yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
169 die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
170 must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
171 main() {
172 # Validate inputs
173 local groupName re1 fina;
174 ## Interpret first argument as name of group directory to move files into.
175 groupName="$1"; # e.g. 'keep'
176 ### RegEx matches:
177 ### - Forward slash (i.e. path) anywhere.
178 ### - A string consisting of just '.' (current working dir)
179 ### - A string consisting of just '..' (parent dir of working dir)
180 re1='/|^\.$|^\.\.$';
181 if [[ "$groupName" =~ $re1 ]]; then
182 die "FATAL:Group '${groupName}' must not be a path.";
183 fi;
184 if [[ -z "$groupName" ]]; then
185 die "FATAL:Group '${groupName}' may not be blank.";
186 fi;
187 shift;
188
189 ## Interpret remaining arguments as files and populate input file array
190 fina=("$@");
191
192 ## Validate input file array
193 ### Handle no argument case.
194 if [[ $# -le 0 ]]; then
195 die "FATAL:No arguments:$#";
196 fi;
197 ### Check each remaining array element is a file.
198 local fin;
199 for fin in "${fina[@]}"; do
200 if [[ ! -f "$fin" ]]; then
201 die "FATAL:Not a file:${fin}";
202 fi;
203 done;
204
205
206 # Process each file
207 local f;
208 for f in "${fina[@]}"; do
209 # Set up variables
210 local fBase dParent dParParent fNoExt dGroup;
211 fBase="$(basename "$f")";
212 dParent="$(dirname "$f")";
213 dParParent="$(dirname "$dParent")";
214 fNoExt="${fBase%.*}";
215 dGroup="${dParParent}/${groupName}";
216 yell "DEBUG:fdebug:${fdebug}";
217 yell "DEBUG:f:${f}"; # e.g. ~/Pics/MyJPGs/DSC00001.JPG
218 yell "DEBUG:fBase:${fBase}"; # e.g. DSC00001.JPG
219 yell "DEBUG:fNoExt:${fNoExt}"; # e.g. DSC00001
220 yell "DEBUG:dParent:${dParent}"; # e.g. ~/Pics/MyJPGs/
221 yell "DEBUG:dParParent:${dParParent}"; # e.g. ~/Pics/
222 yell "DEBUG:dGroup:${dGroup}"; # e.g. ~/Pics/keep/
223
224 # Move sibling files sharing the stem
225 local fSrc subDirName dDest;
226 for fSrc in "${dParParent}"/*/"${fNoExt}".*; do
227 if [ ! -e "$fSrc" ]; then continue; fi;
228 subDirName="$(basename "$(dirname "$fSrc")")";
229 dDest="${dGroup}/${subDirName}";
230 yell "DEBUG:fSrc:${fSrc}"; # e.g. ~/Pics/MyARWs/DSC00001.ARW.ots
231 yell "DEBUG:subDirName:${subDirName}"; # e.g. MyARWs
232 yell "DEBUG:dDest:${dDest}"; # e.g. ~/Pics/keep/MyARWs/
233 if [ ! -d "$dDest" ]; then
234 yell "STATUS:Destination dir does not exist. Creating:${dDest}";
235 must mkdir -p "$dDest";
236 else
237 yell "STATUS:Destination dir exists:${dDest}";
238 fi;
239 yell "STATUS: Moving ${fSrc} β†’ ${dDest}/";
240
241 # Perform move ( e.g. mv ~/Pics/MyARWs/DSC00001.ARW.ots ~/Pics/keep/MyARWs/ )
242 mv -n "$fSrc" "${dDest}/";
243
244 # Check if move failed.
245 if [[ -e "$fSrc" ]]; then
246 yell "ERROR:Failed to move ${fSrc} β†’ ${dDest}";
247 fi;
248 done;
249 done;
250 };
251
252 main "$@" 1>>"$fdebug" 2>&1;
253
254 # Author: Steven Baltakatei Sandoval
255 # License: GPLv3+
256 #+end_code
257