aboutsummaryrefslogtreecommitdiff
path: root/bin/rndl.sh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/rndl.sh')
-rw-r--r--bin/rndl.sh50
1 files changed, 50 insertions, 0 deletions
diff --git a/bin/rndl.sh b/bin/rndl.sh
new file mode 100644
index 00000000..18bcec07
--- /dev/null
+++ b/bin/rndl.sh
@@ -0,0 +1,50 @@
+# Print a random line from input
+self=rndl
+
+# If there are no arguments, we're checking stdin; this is more complicated
+# than checking file arguments because we have to count the lines in order to
+# correctly choose a random one, and two passes means we require a temporary
+# file if we don't want to read all of the input into memory (!)
+if [ "$#" -eq 0 ] ; then
+
+ # Create a temporary directory with name in $td, and handle POSIX-ish traps to
+ # remove it when the script exits.
+ td=
+ cleanup() {
+ [ -n "$td" ] && rm -fr -- "$td"
+ if [ "$1" != EXIT ] ; then
+ trap - "$1"
+ kill "-$1" "$$"
+ fi
+ }
+ for sig in EXIT HUP INT TERM ; do
+ # shellcheck disable=SC2064
+ trap "cleanup $sig" "$sig"
+ done
+ td=$(mktd "$self") || exit
+
+ # We'll operate on stdin in the temp directory; write the script's stdin to
+ # it with cat(1)
+ set -- "$td"/stdin
+ cat >"$td"/stdin
+fi
+
+# Count the number of lines in the input
+lc=$(sed -- '$=;d' "$@") || exit
+
+# If there were none, bail
+case $lc in
+ ''|0)
+ printf >&2 'rndl: No lines found on input\n'
+ exit 2
+ ;;
+esac
+
+# Try to get a random seed from rnds(1df) for rndi(1df)
+seed=$(rnds)
+
+# Get a random line number from rndi(1df)
+ri=$(rndi 1 "$lc" "$seed") || exit
+
+# Print the line using sed(1)
+sed -- "$ri"'!d' "$@"