]> zdv2.bktei.com Git - BK-2020-03.git/commitdiff
feat(user/gthumb/prune.org):Prune files via gThumb
authorSteven Baltakatei Sandoval <baltakatei@gmail.com>
Sat, 1 Aug 2026 19:04:46 +0000 (19:04 +0000)
committerSteven Baltakatei Sandoval <baltakatei@gmail.com>
Sat, 1 Aug 2026 19:04:46 +0000 (19:04 +0000)
user/gthumb/prune.org [new file with mode: 0644]

diff --git a/user/gthumb/prune.org b/user/gthumb/prune.org
new file mode 100644 (file)
index 0000000..d9d211e
--- /dev/null
@@ -0,0 +1,257 @@
+#+AUTHOR: Steven Baltakatei Sandoval
+#+DATE: 2026-08-01
+#+TITLE: gThumb prune
+
+** Summary
+This work describes a way to quickly move groups of photograph files
+(e.g. ~DSC00001.JPG~, ~DSC00001.ARW~, etc.) as well as associated
+sidecar files into desired directories via keyboard shortcuts in
+gThumb.
+
+The method centers around a Bash script named ~gthumb-prune.sh~ which
+may be bound to a gThumb keyboard shortcut to quickly move selected
+image files to a desired location. The Bash script is run by a short
+shell script specified in gThumbΚΌs πŸ”§ β†’ Personalize…  menu.
+Additionally, sidecar files as well as associated files sharing the
+same file name stem (i.e. ~../*/DSC00001.*~) are also grouped and
+moved to the desired location.
+
+** Stats
+Version: 0.0.4
+License: GPLv3+
+gThumb version: ~3.12.6~
+
+** Usage
+Let us say, that we have a set of photos in the following
+locations:
+
+#+begin_example
+.
+β”œβ”€β”€ ARW
+β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
+β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
+β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
+β”‚Β Β  β”œβ”€β”€ DSC00002.ARW.ots
+β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
+β”‚Β Β  β””── DSC00003.ARW.ots
+└── JPG
+    β”œβ”€β”€ DSC00001.JPG
+    β”œβ”€β”€ DSC00001.JPG.ots
+    β”œβ”€β”€ DSC00002.JPG
+    β”œβ”€β”€ DSC00002.JPG.ots
+    β”œβ”€β”€ DSC00002.JPG
+    β””── DSC00002.JPG.ots
+#+end_example
+
+Let us say gThumb has the ~JPG~ directory open and we have selected
+~DSC00002.JPG~ which we want to keep.  We also want to keep the
+associated ~DSC00002.JPG.ots~ as well as the ~DSC00002.ARW~ and
+~DSC00002.ARW.ots~ files in the neighboring ~ARW~ directory. We wish
+to discard all other photograph files.
+
+First, we configure a ~keep~ shortcut. In the gThumbΚΌs πŸ”§ β†’
+Personalize…  menu, click the *New* button. Set the *Name* to
+~keep~. Set the *Command* to:
+
+: fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" "keep" %F; fi;
+
+Where ~$HOME/.local/bin/gthumb-prune.sh~ is the path for the Bash
+script (see the ~Code~ section below).
+
+Set the *Shortcut* to ~Shift+K~. Make sure the box β€œTerminal command
+(shell script)” box is checked and the β€œExecute command once for every
+file” is *not* checked. Click the *Save* button to close the ~Edit
+Command~ window. Click the *Ok* button to close the ~Commands~ window.
+
+Now, with ~DSC00002.JPG~ selected, press ~Shift+K~ on your
+keyboard. The image should disappear from view and a new directory
+should appear in the the left navbar, reflecting a new directory structure.
+
+#+begin_example
+.
+β”œβ”€β”€ ARW
+β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
+β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
+β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
+β”‚Β Β  β””── DSC00003.ARW.ots
+β”œβ”€β”€ JPG
+β”‚Β Β  β”œβ”€β”€ DSC00001.JPG
+β”‚Β Β  β”œβ”€β”€ DSC00001.JPG.ots
+β”‚Β Β  β”œβ”€β”€ DSC00003.JPG
+β”‚Β Β  β””── DSC00003.JPG.ots
+└── keep
+    β”œβ”€β”€ ARW
+    β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
+    β”‚Β Β  β””── DSC00002.ARW.ots
+    β””── JPG
+        β”œβ”€β”€ DSC00002.JPG
+        β””── DSC00002.JPG.ots
+#+end_example
+
+The ~DSC0002.*~ files (4 in total) have been moved to now reside
+within a ~keep~ directory with their ~JPG~ and ~ARW~ subdirectory
+structure preserved. Thus, the ~./JPG/~ and ~./ARW/~ directories have
+been pruned.
+
+If we want to trash the remaining ~DSC00001.*~ and ~DSC00003.*~ files,
+we can create another shortcut to group and move files into a ~.trash~
+directory next to ~keep~.
+
+Repeat the procedure for creating a shortcut, but *Name* it ~rmall~
+and set the *Command* to be:
+
+: fscript="$HOME/.local/bin/gthumb-prune.sh"; if [ -f "$fscript" ]; then /bin/bash "$fscript" ".trash" %F; fi;
+
+Note the change from ~keep~ to ~.trash~. Set the keyboard *Shortcut*
+to ~Shift+T~.
+
+Now, with gThumb looking at the contents of ~./JPG~, and with
+~DSC00001.JPG~ and ~DSC00003.JPG~ selected, press ~Shift+T~. The two
+images should disappear, leaving ~./JPG~ now empty.  The navbar to the
+left should not show any change since ~.trash~ is a dot directory and
+so is normally hidden.  Nonetheless, the directory structure has now
+changed to:
+
+#+begin_example
+.
+β”œβ”€β”€ ARW
+β”œβ”€β”€ JPG
+β”œβ”€β”€ keep
+β”‚Β Β  β”œβ”€β”€ ARW
+β”‚Β Β  β”‚Β Β  β”œβ”€β”€ DSC00002.ARW
+β”‚Β Β  β”‚Β Β  β””── DSC00002.ARW.ots
+β”‚Β Β  β””── JPG
+β”‚Β Β      β”œβ”€β”€ DSC00002.JPG
+β”‚Β Β      β””── DSC00002.JPG.ots
+└── .trash
+    β”œβ”€β”€ ARW
+    β”‚Β Β  β”œβ”€β”€ DSC00001.ARW
+    β”‚Β Β  β”œβ”€β”€ DSC00001.ARW.ots
+    β”‚Β Β  β”œβ”€β”€ DSC00003.ARW
+    β”‚Β Β  β””── DSC00003.ARW.ots
+    β””── JPG
+        β”œβ”€β”€ DSC00001.JPG
+        β”œβ”€β”€ DSC00001.JPG.ots
+        β”œβ”€β”€ DSC00003.JPG
+        β””── DSC00003.JPG.ots
+#+end_Example
+
+So, the contents of ~./JPG/~ may be pruned by selecting files you want
+to keep and pressing ~Shift+K~ and by selecting files you want to
+trash and pressing ~Shift+T~. Then, if you are really sure about
+deleting the undesired files, delete the contents of ~.trash~ via the
+terminal command:
+
+: $ rm -r ./.trash/*
+
+** Code
+gthumb-prune.sh:
+
+#+begin_code
+#!/bin/bash
+# Desc: Prunes files selected by gThumb.
+# Note: Moves files into a directory with a specified name.
+# Usage: gthumb-prune.sh [STR dirname] [FILES…]
+# Example: $HOME/.local/bin/gthumb-prune.sh keep %F
+#   If '%F' expanded to `~/Pics/MyJPGs/DSC00001.JPG`, then
+#     "$HOME/Pics/*/DSC00001.*" files are moved to:
+#     '~/Pics/keep/MyJPGs/' .
+#
+#   If '%F' expanded to multiple files, then the move
+#     operations to 'keep' are performed for each file.
+# Input: arg1   str  directory to send selected files
+#        arg2+  str  path of selected file(s)
+# Version: 0.0.4
+
+fdebug=/tmp/gtPruneLog.txt;
+
+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
+main() {
+    # Validate inputs
+    local groupName re1 fina;
+    ## Interpret first argument as name of group directory to move files into.    
+    groupName="$1";   # e.g. 'keep'
+    ### RegEx matches:
+    ###   - Forward slash (i.e. path) anywhere.
+    ###   - A string consisting of just '.' (current working dir)
+    ###   - A string consisting of just '..' (parent dir of working dir)
+    re1='/|^\.$|^\.\.$'; 
+    if [[ "$groupName" =~ $re1 ]]; then
+        die "FATAL:Group '${groupName}' must not be a path.";
+    fi;
+    if [[ -z "$groupName" ]]; then
+        die "FATAL:Group '${groupName}' may not be blank.";
+    fi;
+    shift;
+    
+    ## Interpret remaining arguments as files and populate input file array
+    fina=("$@");
+
+    ## Validate input file array
+    ### Handle no argument case.
+    if [[ $# -le 0 ]]; then
+        die "FATAL:No arguments:$#";
+    fi;
+    ### Check each remaining array element is a file.
+    local fin;
+    for fin in "${fina[@]}"; do
+        if [[ ! -f "$fin" ]]; then
+            die "FATAL:Not a file:${fin}";
+        fi;
+    done;
+
+    
+    # Process each file
+    local f;
+    for f in "${fina[@]}"; do
+        # Set up variables
+        local fBase dParent dParParent fNoExt dGroup;
+        fBase="$(basename "$f")";      
+        dParent="$(dirname "$f")";        
+        dParParent="$(dirname "$dParent")";    
+        fNoExt="${fBase%.*}";             
+        dGroup="${dParParent}/${groupName}";
+        yell "DEBUG:fdebug:${fdebug}";
+        yell "DEBUG:f:${f}";                   # e.g. ~/Pics/MyJPGs/DSC00001.JPG
+        yell "DEBUG:fBase:${fBase}";           # e.g. DSC00001.JPG
+        yell "DEBUG:fNoExt:${fNoExt}";         # e.g. DSC00001
+        yell "DEBUG:dParent:${dParent}";       # e.g. ~/Pics/MyJPGs/
+        yell "DEBUG:dParParent:${dParParent}"; # e.g. ~/Pics/
+        yell "DEBUG:dGroup:${dGroup}";         # e.g. ~/Pics/keep/
+
+        # Move sibling files sharing the stem
+        local fSrc subDirName dDest;
+        for fSrc in "${dParParent}"/*/"${fNoExt}".*; do         
+            if [ ! -e "$fSrc" ]; then continue; fi;
+            subDirName="$(basename "$(dirname "$fSrc")")";  
+            dDest="${dGroup}/${subDirName}";
+            yell "DEBUG:fSrc:${fSrc}";                  # e.g. ~/Pics/MyARWs/DSC00001.ARW.ots
+            yell "DEBUG:subDirName:${subDirName}";      # e.g. MyARWs
+            yell "DEBUG:dDest:${dDest}";                # e.g. ~/Pics/keep/MyARWs/
+            if [ ! -d "$dDest" ]; then
+                yell "STATUS:Destination dir does not exist. Creating:${dDest}";
+                must mkdir -p "$dDest";
+            else
+                yell "STATUS:Destination dir exists:${dDest}";
+            fi;
+            yell "STATUS: Moving ${fSrc} β†’ ${dDest}/";
+
+            # Perform move ( e.g. mv ~/Pics/MyARWs/DSC00001.ARW.ots ~/Pics/keep/MyARWs/ )
+            mv -n "$fSrc" "${dDest}/";
+
+            # Check if move failed.
+            if [[ -e "$fSrc" ]]; then
+                yell "ERROR:Failed to move ${fSrc} β†’ ${dDest}";
+            fi;
+        done;
+    done;
+};
+
+main "$@" 1>>"$fdebug" 2>&1;
+
+# Author: Steven Baltakatei Sandoval
+# License: GPLv3+
+#+end_code
+