1 #+AUTHOR: Steven Baltakatei Sandoval
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
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.
22 gThumb version: ~3.12.6~
25 Let us say, that we have a set of photos in the following
31 βΒ Β βββ DSC00001.ARW
32 βΒ Β βββ DSC00001.ARW.ots
33 βΒ Β βββ DSC00002.ARW
34 βΒ Β βββ DSC00002.ARW.ots
35 βΒ Β βββ DSC00003.ARW
36 βΒ Β βββ DSC00003.ARW.ots
38 βββ DSC00001.JPG
39 βββ DSC00001.JPG.ots
40 βββ DSC00002.JPG
41 βββ DSC00002.JPG.ots
42 βββ DSC00003.JPG
43 βββ DSC00003.JPG.ots
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.
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:
56 : fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" "keep" %F; fi;
58 Where ~$HOME/.local/bin/gthumb-prune.sh~ is the path for the Bash
59 script (see the ~Code~ section below).
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.
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 left navbar, reflecting a new directory structure.
73 βΒ Β βββ DSC00001.ARW
74 βΒ Β βββ DSC00001.ARW.ots
75 βΒ Β βββ DSC00003.ARW
76 βΒ Β βββ DSC00003.ARW.ots
78 βΒ Β βββ DSC00001.JPG
79 βΒ Β βββ DSC00001.JPG.ots
80 βΒ Β βββ DSC00003.JPG
81 βΒ Β βββ DSC00003.JPG.ots
84 βΒ Β βββ DSC00002.ARW
85 βΒ Β βββ DSC00002.ARW.ots
87 βββ DSC00002.JPG
88 βββ DSC00002.JPG.ots
91 The ~DSC00002.*~ 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
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~.
100 Repeat the procedure for creating a shortcut, but *Name* it ~rmall~
101 and set the *Command* to be:
103 : fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" ".trash" %F; fi;
105 Note the change from ~keep~ to ~.trash~. Set the keyboard *Shortcut*
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
121 βΒ Β βΒ Β βββ DSC00002.ARW
122 βΒ Β βΒ Β βββ DSC00002.ARW.ots
124 βΒ Β βββ DSC00002.JPG
125 βΒ Β βββ DSC00002.JPG.ots
128 βΒ Β βββ DSC00001.ARW
129 βΒ Β βββ DSC00001.ARW.ots
130 βΒ Β βββ DSC00003.ARW
131 βΒ Β βββ DSC00003.ARW.ots
133 βββ DSC00001.JPG
134 βββ DSC00001.JPG.ots
135 βββ DSC00003.JPG
136 βββ DSC00003.JPG.ots
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
152 # Desc: Prunes files selected by gThumb.
153 # Note: Moves files into a directory with a specified name.
154 # Usage: gthumb-prune.sh 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/' .
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)
166 fdebug=/tmp/gtPruneLog.txt;
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
173 local groupName re1 fina;
174 ## Interpret first argument as name of group directory to move files into.
175 groupName="$1"; # e.g. 'keep'
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)
181 if [[ "$groupName" =~ $re1 ]]; then
182 die "FATAL:Group '${groupName}' must not be a path.";
184 if [[ -z "$groupName" ]]; then
185 die "FATAL:Group '${groupName}' may not be blank.";
189 ## Interpret remaining arguments as files and populate input file array
192 ## Validate input file array
193 ### Handle no argument case.
194 if [[ $# -le 0 ]]; then
195 die "FATAL:No arguments:$#";
197 ### Check each remaining array element is a file.
199 for fin in "${fina[@]}"; do
200 if [[ ! -f "$fin" ]]; then
201 die "FATAL:Not a file:${fin}";
208 for f in "${fina[@]}"; do
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/
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";
237 yell "STATUS:Destination dir exists:${dDest}";
239 yell "STATUS: Moving ${fSrc} β ${dDest}/";
241 # Perform move ( e.g. mv ~/Pics/MyARWs/DSC00001.ARW.ots ~/Pics/keep/MyARWs/ )
242 mv -n "$fSrc" "${dDest}/";
244 # Check if move failed.
245 if [[ -e "$fSrc" ]]; then
246 yell "ERROR:Failed to move ${fSrc} β ${dDest}";
252 main "$@" 1>>"$fdebug" 2>&1;
254 # Author: Steven Baltakatei Sandoval