From d441c4b8a8a034fdc54dd3bba9a696818677eee8 Mon Sep 17 00:00:00 2001 From: oh4 <7767846+iamteedoh@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:26:15 -0400 Subject: [PATCH] DIR-5: bring the README up to date with v0.3.0 Three releases of behavior landed and parts of the README still described the tool as it was before. Audit the whole file against what it actually does. Document tab completion. The prompt has completed paths since readline arrived alongside the arrow-key history, and nothing said so, which means nobody would ever try it. The keys table records what was verified over a pty rather than what readline is assumed to do: completion fills the common prefix and beeps on an ambiguity without listing the candidates, which is where `read -e` differs from an interactive shell. Correct what had gone stale: the Overview still described prompting for an input file rather than a session; a feature bullet still advertised the `owner rwx | group r-x | other r--` string that the table replaced; the "prompts for the rest" paragraph had drifted under the "Paths vs. lists" heading during earlier edits; Prerequisites named neither the Bash 3.2 floor nor the tty the session needs; Installation predated the repository having releases. Document exit codes. The README recommends the tool for cron and CI without saying that a denied permission exits 0 and only a usage error exits 2, so `dirPathPerms.sh ... || alert` never fires. Say so, and show a recipe that reads the output instead. --- README.md | 131 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 52fee44..5ebe562 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,20 @@ ## Overview -This Bash script checks specific file or directory permissions (Owner, Group, or Other; Read, Write, or Execute) for the paths you give it — either named directly, or listed one per line in an input file. It provides clear, color-coded output indicating whether the specified permission is set for each path. +This Bash script checks specific file or directory permissions (Owner, Group, or Other; Read, Write, or Execute) for the paths you give it — either named directly, or listed one per line in an input file. Results come back as a color-coded table, one row per path. -It greets you with a big title banner and a short description, then runs either -**interactively** — prompting for the input file and the permission to check — -or **non-interactively** via command-line flags, which makes it easy to drop -into scripts and CI. When any required value is omitted and a terminal is -attached, the script prompts for it; when nothing is attached (a pipe or CI -job), it fails fast with a clear message instead of hanging. +It greets you with a big title banner and a short description, then runs in one +of two modes: + +* **Interactively**, as a session: it asks for a path, shows the table, then + asks for the next one — with tab completion and arrow-key history — until you + press `q`. +* **Non-interactively** via command-line flags, checking once and exiting, which + makes it easy to drop into scripts and CI. + +When a required value is omitted and a terminal is attached, the script prompts +for it; when nothing is attached (a pipe or CI job), it fails fast with a clear +message instead of hanging.

dirPathPerms banner and permission-check output @@ -39,12 +45,13 @@ This script is useful for: (`--path`/`--file`, `--who`, `--perm`) for scripting and CI. * **Check a path directly** with `--path` (repeatable) or a bare argument — no need to author a list file just to check one directory. -* Checks permissions for files and directories listed in a specified input file. +* **Audit many paths at once** from an input file, one path per line. * **Interactive session:** run it with no arguments and it keeps asking for paths until you press `q`, so checking ten paths does not mean launching it ten times. -* **Command-line history:** the interactive prompt supports arrow-key recall and - full line editing, so a typo does not mean retyping the whole path. +* **Tab completion and history:** the prompt completes paths with `Tab`, recalls + earlier entries with the up and down arrows, and supports the usual + line-editing keys — so a typo does not mean retyping the whole path. * **Results as a table:** one row per path, with headers and alternating row shading so adjacent rows stay easy to tell apart. * Allows checking for Owner (`u`), Group (`g`), or Other (`o`) permissions, or @@ -52,21 +59,23 @@ This script is useful for: * Allows checking for Read (`r`), Write (`w`), or Execute (`x`) permissions, or **all three at once** with `--perm all`. Combine with `--all` for the full 3×3 matrix of every permission against every class. -* Interactive prompts guide the user to select the input file and the desired - permission check, and validate every choice. +* Interactive prompts guide the user to choose what to check, and validate every + choice. * Clear, color-coded output: * **Green (`YES`)**: The specified permission is set. * **Red (`NO`)**: The specified permission is **not** set. -* A **summary line** at the end with granted / denied / skipped counts. -* Displays the full permission string (e.g., `owner rwx | group r-x | other r--`) - for context in the output. +* A **summary line** with granted / denied / skipped counts, which switches to + counting individual permission checks when a matrix is shown. +* A **`Mode` column** showing each path's actual mode (e.g. `-rw-r--r--`) for + context, or why there is no result. * **Comment & blank-line support:** lines in the input file that are empty or start with `#` are skipped, including indented ones. * **Forgiving path input:** a leading `~`, a `$VAR`, surrounding quotes, backslash-escaped spaces, stray indentation, and Windows (CRLF) line endings are all handled, so a path pasted out of Finder or a terminal just works. Paths are only ever expanded, never executed. -* Gracefully handles and reports paths listed in the input file that do not exist. +* Gracefully handles and reports paths that do not exist, rather than failing the + whole run. * **Cross-platform:** works with both GNU (`stat -c`) and BSD/macOS (`stat -f`) `stat`, so no GNU coreutils install is required on macOS. * Color is disabled automatically when output is piped or redirected, and can be @@ -75,20 +84,35 @@ This script is useful for: ## Prerequisites -* A Bash-compatible shell (standard on most Linux distributions and macOS). +* **Bash 3.2 or newer** — the version macOS still ships, so nothing needs + installing there. Nothing in the script requires Bash 4+. * Standard Unix/Linux command-line utilities, specifically: * `stat` for retrieving file permissions. The script auto-detects GNU (`stat -c '%A'`) and BSD/macOS (`stat -f '%Sp'`) variants, so it works on Linux and macOS out of the box — no GNU coreutils install required. * `read`, `printf`, `tr` (standard shell built-ins / utilities). +* Optional, and only for the extras: + * A **terminal** for the interactive session — tab completion, history, and + the prompts need one. Without a tty the script expects flags and exits + rather than hanging. + * `getent` (Linux) or `dscl` (macOS) to expand `~user` for *another* user. + Your own `~` needs neither. ## Installation -1. Save the script content to a file, for example, `dirPathPerms.sh`. -2. Make the script executable: - ```bash - chmod +x dirPathPerms.sh - ``` +It is a single self-contained script with no build step and no dependencies to +install. Clone the repository, or download `dirPathPerms.sh` from the +[latest release](https://github.com/iamteedoh/dirPathPerms/releases/latest), +then make it executable: + +```bash +git clone https://github.com/iamteedoh/dirPathPerms.git +cd dirPathPerms +chmod +x dirPathPerms.sh +./dirPathPerms.sh --version +``` + +Put it somewhere on your `PATH` if you want it available everywhere. ## How to Run @@ -102,15 +126,38 @@ many to audit at once. ./dirPathPerms.sh ``` -Run with no arguments it becomes a **session**: +Run with no arguments, it becomes a **session**: + +1. Enter **either** a path to check (`~/Documents`) **or** a file listing paths + to check (`myPaths.txt`) — see [how the two are told apart](#paths-vs-lists). +2. Choose whose permissions to check, and which permission to look for. +3. Read the results table, then **enter another path**. The script keeps asking, + reusing your answers from step 2, until you press **`q`**. + +### Editing keys at the prompt + +The path prompt is a full readline prompt, so it behaves like your shell does: + +| Key | Does | +|---|---| +| `Tab` | **Complete the path.** `~/Doc` → `~/Documents/`, `/etc/pass` → `/etc/passwd`. | +| `↑` / `↓` | Recall anything you have already typed this session — handy after a typo. | +| `Ctrl-A` / `Ctrl-E` | Jump to the start / end of the line. | +| `Ctrl-W` | Delete the previous word. | +| `Ctrl-U` | Clear the line. | +| `Ctrl-R` | Reverse-search what you typed earlier. | +| `q` | Quit the session. | + +Two things to expect from completion, which differ slightly from your shell: + +* When a prefix is **ambiguous** it fills in as far as the candidates agree and + then beeps — `/var/lo` becomes `/var/log` with `/var/log` and `/var/logs` both + present. It does not print the list of candidates. +* Completion is reliable for paths starting with `/` or `~`, which is what this + tool wants anyway. -* Enter **either** a path to check (`~/Documents`) **or** a file listing paths - to check (`myPaths.txt`) — see [how the two are told apart](#paths-vs-lists). -* Choose whose permissions to check, and which permission to look for. -* Read the results table, then **enter another path**. The script keeps asking, - reusing your answers, until you press **`q`**. -* Use the **up and down arrows** to recall anything you have already typed this - session, and the usual line-editing keys to fix a typo. +Nothing is written to your shell history — the session's history lives and dies +with the run. ### Non-interactive @@ -143,6 +190,9 @@ scripts, cron jobs, and CI: Supplying everything via flags checks once and exits — no session loop — which is what makes it usable from cron and CI. +If some (but not all) values are provided, the script prompts for the rest when +a terminal is attached, or exits with a helpful error when one is not. +

Paths vs. lists

A bare argument might be the path you want to check, or a file listing paths to @@ -155,9 +205,6 @@ for a list of paths. Use `--path` or `--file` when you want to say which you meant, instead of relying on the guess. -If some (but not all) values are provided, the script prompts for the rest when -a terminal is attached, or exits with a helpful error when one is not. - ### Command-line options | Option | Description | @@ -285,6 +332,24 @@ Summary: 2 path(s) checked, 0 skipped — 11 of 18 permission checks granted. * **`Summary`**: a tally of granted / denied / skipped. When more than one class or permission is shown, it counts individual permission checks instead. +## Exit codes + +| Code | Meaning | +|---|---| +| `0` | The check ran. **This includes runs where permissions were denied or paths were skipped.** | +| `2` | The script could not run the check: an unknown option, a missing option value, no such input file, `--file` and `--path` combined, or nothing to check with no terminal to ask at. | + +> **Reporting a denial is a successful run.** A `NO` in the table does not +> change the exit code, so `dirPathPerms.sh … || echo FAILED` will not fire on a +> denied permission — only on a usage error. Scripts that need to act on the +> result should read the output rather than the exit code: +> +> ```bash +> # alert when the group can write to anything listed +> ./dirPathPerms.sh --file paths.txt --who group --perm write --no-color \ +> | grep -q ' YES ' && echo "group-writable paths found" +> ``` + ## License This project is licensed under the [GNU General Public License v3](LICENSE).