+#!/usr/bin/env bash
+# Desc: Applies chmod to a segment of a directory branch of the
+# filesystem tree. Changes applied to all directories starting with
+# TIP and ending with (but not including) TRUNK.
+
+# Usage: chmoddirbr [path TRUNK] [path TIP]
+# Input: arg1: TRUNK path
+# arg2: TIP path
+# arg3+ arguments to be passed on to chmod
+# Output: None.
+# Depends: GNU Coreutils 8.30 (chmod), Bash 5.0.3
+
+# Example: chmoddirbr /tmp /tmp/1/2/3/4/5/6 o+rx
+# This runs `chmod o+rx /tmp/1/2/3/4/5/6`
+# `chmod o+rx /tmp/1/2/3/4/5`
+# `chmod o+rx /tmp/1/2/3/4`
+# ...
+# `chmod o+rx /tmp/1`
+
+yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
+die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
+try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
+main() {
+ declare -a chmod_args
+ declare -a dirs_branch
+
+ arg1="$1"; shift;
+ arg2="$1"; shift;
+ chmod_args=("$@");
+
+ #yell "DEBUG:arg1:$arg1";
+ #yell "DEBUG:arg2:$arg2";
+ #yell "DEBUG:chmod_args:${chmod_args[@]}";
+
+ # Check input dirs
+ if [[ -d $arg1 ]]; then
+ dir_trunk="$(readlink -f "$arg1")"; # use full path
+ #yell "DEBUG:dir_trunk:$dir_trunk";
+ else
+ die "ERROR:TRUNK is not a dir:$arg1";
+ fi;
+ if [[ -d $arg2 ]]; then
+ dir_tip="$(readlink -f "$arg2")"; # use full path
+ #yell "DEBUG:dir_tip :$dir_tip";
+ else
+ die "ERROR:TIP is not a dir:$arg2";
+ fi;
+
+ # Check if $dir_trunk points to $dir_tip
+ if [[ $dir_tip =~ ^"$dir_trunk" ]]; then
+ :
+ #yell "DEBUG:Tip is within trunk.";
+ else
+ yell "NOTE:dir_trunk:$dir_trunk";
+ yell "NOTE:dir_tip :$dir_tip";
+ die "ERROR:Tip is not within trunk.";
+ fi;
+
+ # Assemble dirs_branch array
+ ## Note: dirs_branch will not include $dir_trunk
+ point="$dir_tip";
+ while [[ $point != $dir_trunk ]]; do
+ #yell "DEBUG:start point :$point";
+ #yell "DEBUG:start dir_trunk:$dir_trunk";
+ dirs_branch+=("$point");
+
+ # Walk up branch
+ point="$(dirname "$point")";
+ #yell "DEBUG:end point :$point";
+ #yell "DEBUG:end dir_trunk:$dir_trunk";
+ #yell ""; # debug
+ done;
+ unset point;
+ #yell "DEBUG:${dirs_branch[@]}";
+
+ # Perform action
+ n=0;
+ for dir in "${dirs_branch[@]}"; do
+ yell "STATUS:$((n+1)):Running: chmod $chmod_args $dir";
+ try chmod "$chmod_args" "$dir" && ((n++));
+ done;
+ yell "STATUS:Finished. Ran chmod $((n)) times.";
+} # main program
+
+main "$@";
+
+# Author: Steven Baltakatei Sandoval
+# License: GPLv3+