Skip to content

Instantly share code, notes, and snippets.

@rsvp
Last active December 25, 2015 15:59
Show Gist options
  • Save rsvp/7002774 to your computer and use it in GitHub Desktop.
Save rsvp/7002774 to your computer and use it in GitHub Desktop.
randout.sh :: readable random output from system kernel using /dev/urandom.
#!/usr/bin/env bash
# bash 4.2.24(1) Linux Ubuntu 12.04 Date : 2013-10-19
#
# _______________| randout : readable random output from system kernel.
#
# Usage: randout [bytes=512] [--TYPE] [characters/line]
# Types: space, graph, mime, url, alpha, alnum, alnoo,
# lonum, hex, digit (see case below for details).
#
# Examples: # Default type is --digit (but --hex is also available):
# $ randout 7
# 9636770
#
# # Types are generally named classes, however, e.g.:
# $ randout 10 --lonum
# 91wkkxf838
#
# # Third arg sets chars/line; otherwise all on one line:
# $ randout 35 --graph 10
# J6zk+2X]6_
# ^f%jY!l;:'
# BV2;SLIGt|
# +./9e
#
#
# Dependencies: /dev/urandom (non-blocking, unlike /dev/random)
# sed (version which accepts \n on RHS of substitution)
# CHANGE LOG LATEST version available: https://bitbucket.org/rsvp/gists/src
#
# 2013-10-19 Add url type, Base64 safe for URL and filename per RFC 4648.
# Re Base64: http://en.wikipedia.org/wiki/Base64
# 2013-10-18 Add alnoo type = alnum without O or o letters.
# Fix range to A-Z where necessary. Eliminate cat pipe; faster.
# 2013-10-11 Fix sed for one EOL per non-empty line. Add mime type.
# 2013-10-10 First version; for exposition, see
# https://source.quora.com/Source-of-randomness-in-Linux-and-the-U-S-NIST
# Wrote this because U.S. NIST Beacon was part of gov shutdown.
# _____ PREAMBLE_v2: settings, variables, and error handling.
#
LC_ALL=POSIX
# locale means "ASCII, US English, no special rules,
# output per ISO and RFC standards."
# Esp. use ASCII encoding for glob and sorting characters.
shopt -s extglob
# ^set extended glob for pattern matching.
shopt -s failglob
# ^failed pattern matching signals error.
set -e
# ^errors checked: immediate exit if a command has non-zero status.
set -u
# ^unassigned variables shall be errors.
# Example of default VARIABLE ASSIGNMENT: arg1=${1:-'foo'}
arg1=${1:-'64'}
# ^number of output bytes.
arg2=${2:-'--digit'}
# ^type of string
arg3=${3:-$arg1}
# ^characters per line (PGP uses 64).
program=${0##*/} # similar to using basename
memf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX )
cleanup () {
# Delete temporary files, then optionally exit given status.
local status=${1:-'0'}
rm -f $memf
[ $status = '-1' ] || exit $status # thus -1 prevents exit.
} #--------------------------------------------------------------------
warn () {
# Message with basename to stderr. Usage: warn "message"
echo -e "\n !! ${program}: $1 " >&2
} #--------------------------------------------------------------------
die () {
# Exit with status of most recent command or custom status, after
# cleanup and warn. Usage: command || die "message" [status]
local status=${2:-"$?"}
cleanup -1 && warn "$1" && exit $status
} #--------------------------------------------------------------------
trap "die 'SIG disruption, but cleanup finished.' 114" 1 2 3 15
# Cleanup after INTERRUPT: 1=SIGHUP, 2=SIGINT, 3=SIGQUIT, 15=SIGTERM
#
# _______________ :: BEGIN Script ::::::::::::::::::::::::::::::::::::::::
# # 2013-10-10 My one-liner for digit case explained. Case added later.
#
# cat /dev/urandom | strings --all | sed -e 's/[^0-9]//g' | tr -d '\n' \
# | head --bytes=$arg1
#
# # From /dev/urandom filter out everything except readable characters for sed
# # which will then accept only digits, but tr is needed to remove line returns.
# # Finally use head to limit the stream output to default 512 bytes.
# This whole paragraph is actually an ONE-LINER...
strings --all /dev/urandom \
| case "$arg2" in
'--space') cat ;;
# ^Include space and TAB
'--graph') sed -e 's/[[:space:]]*//g' ;;
# ^Non-space characters
'--mime') sed -e 's/[^0-9A-Za-z+/]//g' ;;
# ^ALPHANUMERIC / + Base64
# a.k.a. Radix-64 OpenPGP.
# Padding char = not added.
'--url') sed -e 's/[^-0-9A-Za-z_]//g' ;;
# ^ALPHANUMERIC - _ Base64
# Filename safe RFC 4648.
'--alnum') sed -e 's/[^0-9A-Za-z]//g' ;;
# ^ALPHANUMERIC
'--alnoo') sed -e 's/[^0-9A-NP-Za-np-z]//g' ;;
# ^ALPHANUMERIC less O & o
# thus zero is distinctive.
'--alpha') sed -e 's/[^A-Za-z]//g' ;;
# ^ALPHA characters only
'--lonum') sed -e 's/[^0-9a-z]//g' ;;
# ^Lower case w/ numbers
'--hex') sed -e 's/[^0-9A-F]//g' ;;
# ^HEX
'--digit') sed -e 's/[^0-9]//g' ;;
# ^DIGITS only.
*) die "undefined arg: $arg2" 113 ;;
esac \
| tr -d '\n' | head --bytes=$arg1 \
| sed -e "s/.\{$arg3\}/&\n/g" -e 's/$/\n/' \
| sed -e '/^$/d'
# First part of sed break up the stream into lines
# of fixed length given by arg3. The second part
# insures that the stream always ends with EOL.
# The final sed is needed to re-read the stream,
# then delete any blank lines for consistent output,
# i.e. a line always ends with EOL.
cleanup
# _______________ EOS :: END of Script ::::::::::::::::::::::::::::::::::::::::
# vim: set fileencoding=utf-8 ff=unix tw=78 ai syn=sh :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment