]> zdv2.bktei.com Git - BK-2020-03.git/commitdiff
Merge remote-tracking branch 'zdv2/develop' into develop develop
authorSteven Baltakatei Sandoval <baltakatei@gmail.com>
Thu, 3 Sep 2026 22:45:21 +0000 (22:45 +0000)
committerSteven Baltakatei Sandoval <baltakatei@gmail.com>
Thu, 3 Sep 2026 22:45:21 +0000 (22:45 +0000)
unitproc/bkt-sum_float [new file with mode: 0755]
unitproc/bkt-yellDieMust
unitproc/find_erotica.sh
user/gthumb/gthumb-analyze.sh [new file with mode: 0644]
user/gthumb/prune.org [new file with mode: 0644]
user/mw_wc2sp.sh
user/ping_offline.sh

diff --git a/unitproc/bkt-sum_float b/unitproc/bkt-sum_float
new file mode 100755 (executable)
index 0000000..0c5c402
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Desc: Sums newline-delimited floats received from stdin
+# Usage: some_app | sumFloat
+# Example: printf -- "-3\n0.14" | sumFloat
+#   Result: -2.860000
+# Version: 0.0.2
+# Depends: bc 1.07.1
+
+yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
+dief() { yell "$*"; return 111; } # same as yell() but non-zero return status
+must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
+sum_float() {
+    # Desc: Sums newline-delimited floats received on stdin
+    # Usage: some_app | sum_float
+    # Depends: bc 1.07.1, paste (GNU coreutils)
+
+    # Check dependencies
+    command -v bc 1>/dev/random 2>&1 || { dief "FATAL:Missing:bc"; };
+    [[ ! -t 0 ]] || { dief "FATAL:No stdin detected."; };
+
+    # Process lines
+    local line re; local -a nums=();
+    re='^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$';
+    while IFS= read -r line; do
+        [[ -z $line ]] && continue;
+        [[ $line =~ $re ]] || { dief "FATAL:Not a float:${line}"; };
+        nums+=("$line");
+    done;
+
+    # Print output
+    if (( ${#nums[@]} == 0 )); then printf '0.000000\n'; return 0; fi;
+    LC_ALL=C printf '%.6f\n' "$(printf '%s\n' "${nums[@]}" | paste -sd+ - | bc -l)";
+} # sum stdin floats
+
+# Author: Steven Baltakatei Sandoval
+# License: GPLv3+
index 5d604ba02c92a3c29fe9ba92bb2be54e0a6a7a99..84a8fec65642feb856044a130f2e9c26b4a33f0f 100644 (file)
@@ -4,7 +4,7 @@
 # Note: All three functions should be added together if used at all.
 # Ref/Attrib: [1] Yell, Die, Try Three-Fingered Claw technique https://stackoverflow.com/a/25515370
 # Depends: GNU Coreutils 8.30
-# Version 1.0.0
+# Version 1.0.1
 
 #==BEGIN Define script parameters==
 #==END Define script parameters==
@@ -12,6 +12,7 @@
 #===BEGIN Declare local script functions===
 yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
 die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
+dief() { yell "$*"; return 111; } # same as die() but meant for functions to avoid exiting main shell
 must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
 #===END Declare local script functions===
 
index 15020989b600698d02135a6790492a22d01be2f0..4b073b95a01e5a5752c4e9a734acbbe1e95efcec 100755 (executable)
@@ -2,7 +2,7 @@
 # Desc: Searches for erotic phrases in text files in specified working directory
 # Usage: find_erotica.sh [dir]
 # Depends: GNU Find utils, GNU Parallel 20210822, GNU Grep, GNU Coreutils 8.32, bc
-# Version: 0.3.0
+# Version: 0.4.0
 
 
 FIN_MAX=400;
@@ -282,10 +282,13 @@ find_phrase () {
     #printf "Found %d matching lines for phrases in %s.\n" "${#output[@]}" "$fin" 1>&2; # debug
 }; # find phrase
 main () {
-    din="$1";
-    if [[ ! -d "$din" ]]; then die "FATAL:Not a dir:${din}"; fi;
+    # Check args are dirs
+    local item;
+    for item in "$@"; do
+        if [[ ! -d "$item" ]]; then die "FATAL:Not a dir:${din}"; fi;
+    done;
 
-    find "$din" -type f -name "*.txt" | shuf | head -n "$FIN_MAX" | \
+    find "$@" -type f -name "*.txt" | shuf | head -n "$FIN_MAX" | \
         #parallel search_thread '{}' | less --RAW-CONTROL-CHARS -S;
         parallel search_thread '{}';
 };
diff --git a/user/gthumb/gthumb-analyze.sh b/user/gthumb/gthumb-analyze.sh
new file mode 100644 (file)
index 0000000..430b77d
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/bash
+# Desc: Analyzes photo files selected in gThumb; shows size/time/GPS
+#   statistics in a zenity dialog. Intended for evaluating burst-mode
+#   sequences where larger JPEG size correlates with sharpness.
+# Usage: gthumb-analyze.sh FILE…
+# Example: $HOME/.local/bin/gthumb-analyze.sh %F
+# Depends: bash, GNU coreutils, awk, bc, column (util-linux 2.39.3)
+#   exiftool (12.x), GNU sed 4.9, zenity
+# Version: 0.0.9
+
+fdebug=/tmp/gtAnalyzeLog.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 fina fin cmd;
+    fina=("$@");
+    if [[ $# -le 0 ]]; then die "FATAL:No arguments:$#"; fi;
+    for fin in "${fina[@]}"; do
+        if [[ ! -f "$fin" ]]; then die "FATAL:Not a file:${fin}"; fi;
+    done;
+    for cmd in awk bc column cut exiftool sed sort zenity; do
+        command -v "$cmd" >/dev/null 2>&1 || die "FATAL:Missing dependency:${cmd}";
+    done;
+
+    # Single batched exiftool pass. Columns (tab-separated):
+    #   col 1: FileName
+    #   col 2: FileSize [bytes]
+    #   col 3: SubSecCreateDate [float POSIX seconds]
+    #   col 4: GPSPosition [±Lat, ±Lon]
+    #   col 5: FNumber [float]
+    #   col 6: ExposureTime [str seconds]
+    #   col 7: ISO [int]
+    #   col 8: FocalLength [str %.01f mm]
+    # Note: Missing tags emit '-' in -T mode.
+    local tsv;
+    tsv="$(exiftool -q -T -FileName '-FileSize#' \
+        -SubSecCreateDate -d '%s%f' \
+        -GPSPosition -c '%+0.4f' \
+        -FNumber -ExposureTime -ISO -FocalLength \
+        -- "${fina[@]}")" \
+        || die "FATAL:exiftool failed";
+    yell "DEBUG:tsv:"; printf '%s\n' "$tsv" 1>&2;
+
+    local n fMax fMaxArr fMin fMinArr mean sdev median span gps;
+    n="$(printf '%s\n' "$tsv" | wc -l)";
+
+    # First and last by file name
+    local fFirst fLast;
+    fFirst="$(printf '%s\n' "$tsv" | sort -t$'\t' -k1,1 | head -n1 | cut -f1)";
+    fLast="$(printf '%s\n' "$tsv" | sort -t$'\t' -k1,1 | tail -n1 | cut -f1)";
+    
+    # Largest and smallest files by size (numeric sort on column 2)
+    fMax="$(printf '%s\n' "$tsv" | sort -t$'\t' -k2,2n | tail -n1)";
+    fMin="$(printf '%s\n' "$tsv" | sort -t$'\t' -k2,2n | head -n1)";
+    fMaxArr[0]="$(cut -f1 <<< "$fMax")";
+    fMaxArr[1]="$(cut -f2 <<< "$fMax")";
+    fMinArr[0]="$(cut -f1 <<< "$fMin")";
+    fMinArr[1]="$(cut -f2 <<< "$fMin")";
+    ## Avoid & or < being parsed as markup by zenity
+    fMaxArr[0]="$(sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' <<< "${fMaxArr[0]}")";
+    fMinArr[0]="$(sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' <<< "${fMinArr[0]}")";
+
+    # Mean and population standard deviation (÷N, not N−1: the
+    #   selection is the entire population of interest).
+    read -r mean sdev < <(printf '%s\n' "$tsv" | cut -f2 \
+        | awk '{s+=$1; ss+=$1*$1;} END {m=s/NR; printf "%.0f %.0f\n", m, sqrt(ss/NR - m*m);}');
+
+    # Median file size
+    median="$(printf '%s\n' "$tsv" | cut -f2 | sort -n \
+    | awk '{a[i++]=$1;} END {if (i%2==0) {printf "%.0f\n", (a[i/2-1]+a[i/2])/2;} else {print a[int(i/2)];};}')";
+
+    # Time span in seconds via bc; ignore files lacking dates.
+    local tMin tMax;
+    tMin="$(printf '%s\n' "$tsv" | cut -f3 | grep -v '^-$' | sort -n | head -n1)";
+    tMax="$(printf '%s\n' "$tsv" | cut -f3 | grep -v '^-$' | sort -n | tail -n1)";
+    if [[ -n "$tMin" && -n "$tMax" ]]; then
+        span="$(printf "%'.3f s" "$(bc -l <<< "${tMax} - ${tMin}")")"; # seconds
+    else
+        span="n/a (missing SubSecCreateDate)";
+    fi;
+
+    # GPS: single unique value, none, or multiple.
+    local gpsUniq gpsUniqSamp gpsCount;
+    gpsUniq="$(printf '%s\n' "$tsv" | cut -f4 | sort -u | grep -v '^-$')";
+    gpsCount="$(printf '%s\n' "$gpsUniq" | grep -c .)";
+    case "$gpsCount" in
+        0) gps="none";;
+        *) gps="(${gpsCount} distinct)";
+           mapfile -t gpsUniqSamp < <(shuf <<< "$gpsUniq" | head -n8 | sort);;
+    esac;
+
+    # Exposure combos: unique (FNumber, ExposureTime, ISO, FocalLength) tuples.
+    # Missing tags appear as '-' and still compare consistently.
+    local expUniq expUniqSamp expCount exp;
+    expUniq="$(printf '%s\n' "$tsv" | cut -f5-8 | sort -u \
+        | awk -F'\t' '{printf "f/%s\t%s s\tISO %s\t%s\n", $1, $2, $3, $4;}')";
+    mapfile -t expUniqSamp < <(shuf <<< "$expUniq" | head -n8 | sort -t $'\t' -k4,4n);
+    
+    expCount="$(printf '%s\n' "$expUniq" | grep -c .)";
+    case "$expCount" in
+        1) exp="uniform";;
+        *) exp="${expCount} distinct combinations";;
+    esac;
+    
+    # Report
+    local msgSec1Arr msgSec1 msgSec2Arr msgSec2 msgSec3Arr msgSec3 msg;
+    ## Assemble message section 1 (file size, time span)
+    msgSec1Arr+=("$(printf "%d files analyzed (About %d s)" "$n" "$SECONDS")");
+    msgSec1Arr+=("$(printf "First:\t\t%s" "$fFirst")");
+    msgSec1Arr+=("$(printf "Last:\t\t%s" "$fLast")");
+    msgSec1Arr+=("$(printf "%s" "----" )");
+    msgSec1Arr+=("$(printf "Largest:\t%'d B\t%s" "${fMaxArr[1]}" "${fMaxArr[0]}")");
+    msgSec1Arr+=("$(printf "Smallest:\t%'d B\t%s" "${fMinArr[1]}" "${fMinArr[0]}")");
+    msgSec1Arr+=("$(printf "Mean size:\t%'d B" "$mean")");
+    msgSec1Arr+=("$(printf "Median size:\t%'d B" "$median")");
+    msgSec1Arr+=("$(printf "Std. dev.:\t%'d B" "$sdev")");
+    msgSec1Arr+=("$(printf "Time span:\t%s" "$span")");
+    msgSec1="$(printf '%s\n' "${msgSec1Arr[@]}" | column -s $'\t' -t --table-right 2)";
+    ## Assemble message section 2 (location)
+    msgSec2Arr+=("$(printf "GPS:\t%s" "$gps")");
+    msgSec2Arr+=("$(printf '%s\n' "${gpsUniqSamp[@]}")");
+    msgSec2="$(printf '%s\n' "${msgSec2Arr[0]}"; printf '%s\n' "${msgSec2Arr[@]:1}" | column -s $'\t' -t | sed -e 's/^/\t/')";    
+    ## Assemble message section 3 (exposure)
+    msgSec3Arr+=("$(printf "Exposure:\t%s" "$exp")");
+    msgSec3Arr+=("$(printf '%s\n' "${expUniqSamp[@]}")");
+    msgSec3="$(printf '%s\n' "${msgSec3Arr[0]}"; printf '%s\n' "${msgSec3Arr[@]:1}" | column -s $'\t' -t | sed -e 's/^/\t/')";
+    ## Assemble combined message
+    msg="$(printf '%s\n--------\n' "$msgSec1" "$msgSec2" "$msgSec3")";
+    ## Display message
+    zenity --info --title="gThumb-analyze.sh stats" --no-wrap --text="<span font='monospace'>${msg}</span>";
+};
+
+main "$@" 1>>"$fdebug" 2>&1;
+
+# Author: Steven Baltakatei Sandoval
+# License: GPLv3+
+
diff --git a/user/gthumb/prune.org b/user/gthumb/prune.org
new file mode 100644 (file)
index 0000000..81a6d29
--- /dev/null
@@ -0,0 +1,256 @@
+#+AUTHOR: Steven Baltakatei Sandoval
+#+DATE: 2026-08-02
+#+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
+    ├── DSC00003.JPG
+    └── DSC00003.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 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 ~DSC00002.*~ 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_src bash
+#!/bin/bash
+# Desc: Prunes files selected by gThumb.
+# Note: Moves files into a directory with a specified name.
+# Usage: gthumb-prune.sh 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_src
index 467df7a70c54f82e9fa0f927fda3b4734f0086e1..f0981a2bf5024ba2673aec44f34b7e1c1c888a98 100755 (executable)
@@ -4,7 +4,7 @@
 # Input:  arg1  path  input wikicode file
 # Output: files       wikicode file tree
 # Depends: Bash 5.1.16, GNU Coreutils 8.32
-# Version: 0.4.0
+# Version: 0.5.0
 
 re_sp='^(<!-- @subpage:)(.*)([ ]*-->)$'; # subpage marker pattern
 d_out=./wikicode/; # default output dir
@@ -291,7 +291,7 @@ create_output_wikicode() {
 
     # Initialize subpage list wikicode file
     must touch "$p_splwc";
-    printf "==Stats==\n\n==Subpages==\n" >> "$p_splwc";
+    printf "==Stats==\n* Author:\n* Publication date:\n* [[/Combined]]\n\n==Subpages==\n" >> "$p_splwc";
     
     # Read content files according to subpage list file    
     #   Note: $i corresponds to “next” line ($lnext). Therefore, use
index df4a22bceb4fd07ea94e3c2f7484c80c3c536daa..4a6339eb843f82aed6c2337245b7cb95879e66d4 100755 (executable)
@@ -1,17 +1,35 @@
 #!/bin/bash
 # Desc:Marks the time when a remote server can be pinged.
 # Depends: GNU Coreutils 8.32 (date, sleep), iputils-ping 3:20211215-1 (ping)
-# Version: 0.0.2
+# Version: 0.1.0
 
 delay=10;
 domain="google.com"
 
+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
+
 if [[ -n "$1" ]]; then domain="$1"; fi;
 
 SECONDS=0;
 printf "%s:STATUS:Starting ping...\n" "$(date -Is)";
-while ! ping -c1 "$domain"; do
-    sleep "$delay";
+while [[ ! noPing == "true" ]]; do
+    printf "%s:" "$(date -Is)"; # prepend line with date
+    ping -c1 "$domain"; pingExitCode="$?"; # perform ping
+    
+    if [[ "$pingExitCode" -eq 0 ]]; then
+        # Case if ping succeeded
+        printf "%s:Ping resolved after $SECONDS seconds.\n" "$(date -Is)";
+        exit 0;
+    elif [[ "$pingExitCode" -eq 1 ]]; then
+        sleep "$delay";
+        continue;
+    else
+        die "FATAL:Unknown error.";
+        exit 1;
+    fi;
 done;
-printf "%s:Ping resolved after $SECONDS seconds.\n" "$(date -Is)";
-exit 0;
+
+yell "ERROR:Here be dragons.";
+exit 1;