aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2016-12-09 10:16:05 +1300
committerTom Ryder <tom@sanctum.geek.nz>2016-12-09 10:17:34 +1300
commita0acd17ec7a54b2e2fe48b1a98fc7f99cf0d0341 (patch)
tree41bb0d54b40c79ab3f79d4d927c4fd8dd07171c6
parentAdd uts(1df) (diff)
downloaddotfiles-a0acd17ec7a54b2e2fe48b1a98fc7f99cf0d0341.tar.gz
dotfiles-a0acd17ec7a54b2e2fe48b1a98fc7f99cf0d0341.zip
Add chc(1df)
-rw-r--r--README.markdown1
-rwxr-xr-xbin/chc31
-rw-r--r--man/man1/chc.1df35
3 files changed, 67 insertions, 0 deletions
diff --git a/README.markdown b/README.markdown
index 3c692ae5..fd86e656 100644
--- a/README.markdown
+++ b/README.markdown
@@ -419,6 +419,7 @@ Installed by the `install-bin` target:
* `cf(1df)` prints a count of entries in a given directory.
* `cfr(1df)` does the same as `cf(1df)`, but recurses into subdirectories as
well.
+* `chc(1df)` caches the output of a command
* `clrd(1df)` sets up a per-line file read, clearing the screen first.
* `clwr(1df)` sets up a per-line file write, clearing the screen before each
line
diff --git a/bin/chc b/bin/chc
new file mode 100755
index 00000000..b1e4000d
--- /dev/null
+++ b/bin/chc
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Cache the output of a command and emit it straight from the cache if not
+# expired on each run
+
+# First argument is the cache path, second is the duration in seconds
+cac=$1 dur=$2
+shift 2
+
+# Get the current timestamp with uts(1df)
+uts=$(uts) || exit
+
+# Function checks cache exists, is readable, and not expired
+fresh() {
+ [ -f "$cac" ] || return
+ [ -r "$cac" ] || return
+ exp=$(sed 1q -- "$cac") || return
+ [ "$((exp > uts))" -eq 1 ]
+}
+
+# Write runs the command and writes it to the cache
+write() {
+ exp=$((uts + dur))
+ printf '%u\n' "$exp"
+ "$@"
+}
+
+# If the cache isn't fresh, try to write a new one, or bail out
+fresh "$cac" || write "$@" > "$cac" || exit
+
+# Emit the content (exclude the first line, which is the timestamp)
+sed 1d -- "$cac"
diff --git a/man/man1/chc.1df b/man/man1/chc.1df
new file mode 100644
index 00000000..e447d7a7
--- /dev/null
+++ b/man/man1/chc.1df
@@ -0,0 +1,35 @@
+.TH CHC 1df "December 2016" "Manual page for chc"
+.SH NAME
+.B chc
+\- cache the output of a command to avoid running it too often
+.SH USAGE
+.B chc
+CACHE_PATH DURATION COMMAND [ARG1...]
+.SH SYNOPSIS
+.B chc
+/tmp/example.chc 20 curl http://www.example.com/
+.SH DESCRIPTION
+.B chc
+runs the command given in its third argument onwards, and saves the output in
+the file with path given in the first argument, and on each subsequent request
+before the duration in the second argument expires, it emits the content
+directly, rather than running the command. If it's run after the expiry date,
+it runs the command again, and refreshes the cache.
+.P
+This is intended as a quick way to just add three words in front of any given
+expensive command to prevent it running too often. This might be particularly
+useful if a script is called to get data far more often than it actually needs
+to poll to get that data.
+.P
+No file locking is implemented. If you need it, you're probably already at the
+point that you need to write a proper solution, but you could always use Linux
+flock(1) or daemontool's setlock(1) in the command if you're stubborn:
+.P
+ flock -x /var/lock/example.chc chc /var/cache/example.chc 20 curl http://www.example.com/
+.P
+If you want to express the duration in human-readable terms, sec(1df) might be
+useful too.
+.SH SEE ALSO
+sec(1df), uts(1df), flock(1), setlock(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>