aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2016-08-09 17:15:40 +1200
committerTom Ryder <tom@sanctum.geek.nz>2016-08-09 17:20:10 +1200
commit9fb350dc7c8cc5259ef24e0cb097031179fab1d6 (patch)
tree839dd0b8ee3f5323b1cd6aefa22b605b99437d62
parentMention nosls/sls flags in slsf(1) man page (diff)
downloaddotfiles-9fb350dc7c8cc5259ef24e0cb097031179fab1d6.tar.gz
dotfiles-9fb350dc7c8cc5259ef24e0cb097031179fab1d6.zip
Improve commenting/exit handling in binscripts
-rwxr-xr-xbin/cf5
-rwxr-xr-xbin/clrd5
-rwxr-xr-xbin/d2u13
-rwxr-xr-xbin/dub21
-rwxr-xr-xbin/fgscr5
-rwxr-xr-xbin/gms2
-rwxr-xr-xbin/grc10
-rwxr-xr-xbin/gscr16
-rwxr-xr-xbin/hurl8
-rwxr-xr-xbin/igex24
-rwxr-xr-xbin/isgr9
-rwxr-xr-xbin/jfc13
-rwxr-xr-xbin/mkcp14
-rwxr-xr-xbin/mkmv14
-rwxr-xr-xbin/mktd10
-rwxr-xr-xbin/rnda14
-rwxr-xr-xbin/rndf10
-rwxr-xr-xbin/rndi9
-rwxr-xr-xbin/rndl26
-rwxr-xr-xbin/rnds15
-rwxr-xr-xbin/sls8
-rwxr-xr-xbin/slsf1
-rwxr-xr-xbin/stbl9
-rwxr-xr-xbin/stex20
-rwxr-xr-xbin/stws9
-rwxr-xr-xbin/sue11
-rwxr-xr-xbin/u2d13
-rwxr-xr-xbin/urlc3
28 files changed, 287 insertions, 30 deletions
diff --git a/bin/cf b/bin/cf
index feac0236..3ff60156 100755
--- a/bin/cf
+++ b/bin/cf
@@ -1,6 +1,5 @@
#!/bin/sh
# Count entries in a given set of directories
-ex=0
for dir in "${@:-.}" ; do
# Warn if a non-directory was given, flag errors, but continue
@@ -25,4 +24,6 @@ for dir in "${@:-.}" ; do
# Print number of parameters
printf '%u\t%s\n' "$#" "$dir"
done
-exit "$ex"
+
+# Exit non-zero if a non-directory was given as an argument
+exit "${ex:-0}"
diff --git a/bin/clrd b/bin/clrd
index 0e41d2db..0b460671 100755
--- a/bin/clrd
+++ b/bin/clrd
@@ -1,5 +1,8 @@
#!/bin/sh
+# Clear the screen and read a file as it's written line-by-line
self=clrd
+
+# Check we have an input file and are writing to a terminal
if [ "$#" -ne 1 ] ; then
printf >&2 '%s: Need input file\n' "$self"
exit 2
@@ -7,5 +10,7 @@ elif ! [ -t 1 ] ; then
printf >&2 '%s: stdout not a terminal\n' "$self"
exit 2
fi
+
+# Clear the screen and start tailing out the file
clear
tail -f -- "$@"
diff --git a/bin/d2u b/bin/d2u
index a2cb913a..6fe362b7 100755
--- a/bin/d2u
+++ b/bin/d2u
@@ -1,13 +1,26 @@
#!/bin/sh
+# Convert DOS line endings to UNIX ones
+
+# Check arguments
if [ "$#" -eq 0 ] ; then
printf >&2 'd2u: Need a filename\n'
exit 2
fi
+
+# Put a carriage return into a variable for convenience
r=$(printf '\r')
+
+# Iterate over arguments and apply the same ed(1) script to each of them
for fn ; do
+
+ # Note the heredoc WORD is intentionally unquoted because we want to expand
+ # $r within it to get a literal carriage return; the escape characters
+ # prescribed for ed(1) by POSIX are very limited
ed -s -- "$fn" <<EOF || ex=1
g/$r\$/ s/$r\$//
w
EOF
done
+
+# If any of the ed(1) commands failed, we should exit with 1
exit "${ex:-0}"
diff --git a/bin/dub b/bin/dub
index 706c95f0..555bed67 100755
--- a/bin/dub
+++ b/bin/dub
@@ -1,13 +1,32 @@
#!/bin/sh
# List the biggest files in a directory
-dir=$1 lines=${2:-10}
+
+# First optional argument is the directory, defaulting to the
+# current dir; second optional argument is the number of files to
+# show, defaulting to 20
+dir=${1:-.} lines=${2:-10}
+
+# Enter the target dir or bail
cd -- "$dir" || exit
+
+# Add files matching glob, shift them off if unexpanded (first and
+# only entry doesn't exist)
set -- *
[ -e "$1" ] || shift
+
+# Add dot files, shift off the "." and ".." entries (sh(1)
+# implementations seem to vary on whether they include these)
set -- .* "$@"
[ -e "$1" ] || shift
[ "$1" = . ] && shift
[ "$1" = .. ] && shift
+
+# Run du(1) with POSIX compatible flags -k for kilobyte unit and
+# -s for total over the arguments
du -ks -- "$@" |
+
+# Sort the first field (the sizes) numerically, in reverse
sort -k1nr |
+
+# Limit the output to the given number of lines
sed "$lines"q
diff --git a/bin/fgscr b/bin/fgscr
index b95a2d84..510fd7cc 100755
--- a/bin/fgscr
+++ b/bin/fgscr
@@ -1,4 +1,9 @@
#!/bin/sh
# Find all the Git repositories in a directory and scrub them all
+
+# Check we have gscr(1) first
command -v gscr >/dev/null || exit
+
+# Look for any dir named .git in the given (default current) dir and run
+# gscr(1) on it
find "${@:-.}" -name '*.git' -type d -exec gscr {} \;
diff --git a/bin/gms b/bin/gms
index 66b777d1..8479d765 100755
--- a/bin/gms
+++ b/bin/gms
@@ -15,7 +15,7 @@ for sig in EXIT HUP INT TERM ; do
trap "cleanup $sig" "$sig"
done
-# Who am I? Don't trust the environment $UID to tell me.
+# Don't trust the environment $UID, use id(1) instead
uid=$(id -u) || exit
# Iterate through the getmailrc.* files in $GETMAIL if defined, or
diff --git a/bin/grc b/bin/grc
index 9a02d9da..0db91afa 100755
--- a/bin/grc
+++ b/bin/grc
@@ -1,10 +1,16 @@
#!/bin/sh
-# Argument or current dir is a Git repository with uncommitted changes
+# Check whether a directory is a Git repository with uncommitted changes
+
+# Enter given directory or bail
cd -- "${1:-.}" || exit
+
+# If not a Git repository at all, warn explicitly
if ! isgr ; then
printf >&2 'grc: Not a Git repository\n'
exit 1
fi
-isgr || exit
+
+# Exit 0 if the first command gives any output (added files) or the second one
+# exits 1 (inverted; differences in tracked files)
[ -n "$(git ls-files --others --exclude-standard)" ] ||
! git diff-index --quiet HEAD
diff --git a/bin/gscr b/bin/gscr
index 4f7e469c..cac969fe 100755
--- a/bin/gscr
+++ b/bin/gscr
@@ -1,6 +1,13 @@
#!/bin/sh
-# Scrub a Git repository
+# Scrub and pack Git repositories
+
+# Iterate through given directories; default to the current one
for arg in "${@:-.}" ; do (
+
+ # Note the "exit" calls here in lieu of "continue" are deliberate; we're in
+ # a subshell, so leaving it will continue the loop.
+
+ # Enter either bare repository or .git subdir
case $arg in
*.git)
cd -- "$arg" || exit
@@ -9,7 +16,14 @@ for arg in "${@:-.}" ; do (
cd -- "$arg"/.git || exit
;;
esac
+
+ # Check for bad references or other integrity/sanity problems
git fsck || exit
+
+ # Expire dangling references
git reflog expire --expire=now || exit
+
+ # Remove dangling references
git gc --prune=now --aggressive || exit
+
) done
diff --git a/bin/hurl b/bin/hurl
index 7c0b0a33..dcc0fd73 100755
--- a/bin/hurl
+++ b/bin/hurl
@@ -1,5 +1,11 @@
#!/bin/sh
-# Extract <a href="..."> URLs from an HTML document or documents.
+# Extract <a href="..."> URLs from an HTML document or documents
+
+# Input is either stdin or the given arguments concatenated
cat -- "${@:-/dev/stdin}" | # shellcheck disable=SC2002
+
+# Pipe through pup to get all the href links
pup -p 'a attr{href}' |
+
+# Sort them uniquely
sort | uniq
diff --git a/bin/igex b/bin/igex
index 1ca23ecf..c514006d 100755
--- a/bin/igex
+++ b/bin/igex
@@ -1,12 +1,34 @@
#!/bin/sh
-# Run a command and ignore specified exit values.
+# Run a command and ignore specified exit values
+
+# There should be at least two arguments
+if [ "$#" -eq 0 ] ; then
+ printf >&2 'igs: Need an ignore list x,y,z and a command\n';
+fi
+
+# The list of values to ignore is the first argument; add a trailing comma for
+# ease of parsing; shift it off
igs=$1,
shift
+
+# Run the command in the remaining arguments and grab its exit value
"$@"
ex=$?
+
+# Iterate through the ignored exit values by chopping its variable and checking
+# each value until it's empty
while [ -n "$igs" ] ; do
+
+ # Get the first exit value in the remaining list
ig=${igs%%,*}
+
+ # If it matches the command's exit value, exit with 0
[ "$((ig == ex))" -eq 1 ] && exit 0
+
+ # Chop it off the list for the next iteration
igs=${igs#*,}
done
+
+# If we got right through the list, we exit with the same value as the command;
+# i.e. we are not ignoring the value
exit "$ex"
diff --git a/bin/isgr b/bin/isgr
index 9cb37c1a..029b5352 100755
--- a/bin/isgr
+++ b/bin/isgr
@@ -1,8 +1,13 @@
#!/bin/sh
# Return an exit status for whether the current directory appears to be in a
# Git working copy
+
+# No output, at all, ever; this is intended for use in scripting
exec >/dev/null 2>&1
+
+# Enter the given directory (default to current directory)
cd -- "${1:-.}" || exit
+
+# If neither of these commands work, this isn't a Git repository
git symbolic-ref --quiet HEAD ||
-git rev-parse --short HEAD ||
-exit 1
+git rev-parse --short HEAD
diff --git a/bin/jfc b/bin/jfc
index 36e11451..1ac8d16d 100755
--- a/bin/jfc
+++ b/bin/jfc
@@ -1,7 +1,14 @@
#!/bin/sh
-# Commit all changes to a Git repository with a stock message
-# message.
+# Commit all changes to a Git repository with a stock message message
+
+# Enter the given directory, default to the current one
cd -- "${1:-.}" || exit
+
+# Check if there are any changes; if not, don't proceed (but it's not an error)
grc || exit 0
+
+# Add all changes
git add --all || exit
-git commit --message 'Committed by jfc(1)' --quiet || exit
+
+# Quietly commit with a stock message and use its exit value as ours
+git commit --message 'Committed by jfc(1)' --quiet
diff --git a/bin/mkcp b/bin/mkcp
index e5b7b717..37bc87c0 100755
--- a/bin/mkcp
+++ b/bin/mkcp
@@ -1,6 +1,18 @@
#!/bin/sh
# Copy files into created directory in one call
-[ "$#" -gt 2 ] || exit 2
+
+# Check we have at least two arguments
+if [ "$#" -lt 2 ] ; then
+ printf >&2 'mkcp: Need at least one source and destination\n'
+ exit 2
+fi
+
+# Get the last argument (the directory to create)
for dir ; do : ; done
+
+# Create it, or bail
mkdir -p -- "$dir" || exit
+
+# Copy all the remaining arguments into the directory (which will be the last
+# argument)
cp -R -- "$@"
diff --git a/bin/mkmv b/bin/mkmv
index 2dfcd813..803ef05c 100755
--- a/bin/mkmv
+++ b/bin/mkmv
@@ -1,6 +1,18 @@
#!/bin/sh
# Move files into created directory in one call
-[ "$#" -gt 2 ] || exit 2
+
+# Check we have at least two arguments
+if [ "$#" -lt 2 ] ; then
+ printf >&2 'mkmv: Need at least one source and destination\n'
+ exit 2
+fi
+
+# Get the last argument (the directory to create)
for dir ; do : ; done
+
+# Create it, or bail
mkdir -p -- "$dir" || exit
+
+# Move all the remaining arguments into the directory (which will be the last
+# argument)
mv -- "$@"
diff --git a/bin/mktd b/bin/mktd
index 2a8f0e56..afbcf4bb 100755
--- a/bin/mktd
+++ b/bin/mktd
@@ -1,6 +1,12 @@
#!/bin/sh
# Try to make a random temp directory
+
+# Get a random seed from rnds(1); if it's empty, that's still workable
seed=$(rnds)
+
+# Build the intended directory name, with the last element a random integer
+# from 1..2^31
dn=${TMPDIR:-/tmp}/${1:-mktd}.$$.$(rndi 1 2147483648 "$seed")
-mkdir -m 700 -- "$dn" || exit 1
-printf '%s\n' "$dn"
+
+# Create the directory and print its name if successful
+mkdir -m 700 -- "$dn" && printf '%s\n' "$dn"
diff --git a/bin/rnda b/bin/rnda
index 99042bf6..078e5008 100755
--- a/bin/rnda
+++ b/bin/rnda
@@ -1,10 +1,20 @@
#!/bin/sh
-# Choose a random argument using rndi(1).
+# Choose a random argument using rndi(1)
+
+# Check we have at least one argument
if [ "$#" -eq 0 ] ; then
printf >&2 'rnda: No args given\n'
- exit 1
+ exit 2
fi
+
+# Get a random seed from rnds(1); if it's empty, that's still workable
seed=$(rnds)
+
+# Get a random integet from 1 to the number of arguments
argi=$(rndi 1 "$#" "$seed") || exit
+
+# Shift until that argument is the first argument
shift "$((argi-1))"
+
+# Print it
printf '%s\n' "$1"
diff --git a/bin/rndf b/bin/rndf
index 6918dbea..06e15fbe 100755
--- a/bin/rndf
+++ b/bin/rndf
@@ -1,9 +1,17 @@
#!/bin/sh
-# Choose a random file from a given directory using rnda(1). Ignores dot files.
+# Choose a random file from a given directory using rnda(1); ignores dot files
+
+# Directory is first argument; defaults to current directory
dir=${1:-.}
+
+# Set the positional parameters to all the non-dotfiles in that directory
set -- "$dir"/*
+
+# Check for an unexpanded glob (empty directory)
if ! [ -e "$1" ] ; then
printf >&2 'rndf: No files found in %s\n' "$dir"
exit 1
fi
+
+# Print a random argument from the current positional parameters
rnda "$@"
diff --git a/bin/rndi b/bin/rndi
index 3dc8689c..bf78951c 100755
--- a/bin/rndi
+++ b/bin/rndi
@@ -2,13 +2,22 @@
# Get a low-quality random number between two integers. Depending on the awk
# implementation, if you don't provide a third argument (a seed), you might get
# very predictable random numbers based on the current epoch second.
+
BEGIN {
+
+ # Seed with the third argument if given
if (ARGV[3]) {
srand(ARGV[3])
}
+
+ # If not, just seed with what is probably a date/time-derived value
else {
srand()
}
+
+ # Print a random integer bounded by the first and second arguments
print int(ARGV[1]+rand()*(ARGV[2]-ARGV[1]+1))
+
+ # Bail before processing any lines
exit
}
diff --git a/bin/rndl b/bin/rndl
index cb8ac5cc..2ac3bf47 100755
--- a/bin/rndl
+++ b/bin/rndl
@@ -1,6 +1,13 @@
#!/bin/sh
# Print a random line from input
+
+# 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
+
+ # Try to create the temporary directory with mktd(1) safely
td=
cleanup() {
[ -n "$td" ] && rm -fr -- "$td"
@@ -14,10 +21,29 @@ if [ "$#" -eq 0 ] ; then
trap "cleanup $sig" "$sig"
done
td=$(mktd rndl) || 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>&1 'rndl: No lines found on input\n'
+ exit 2
+ ;;
+esac
+
+# Try to get a random seed from rnds(1) for rndi(1)
seed=$(rnds)
+
+# Get a random line number from rndi(1)
ri=$(rndi 1 "$lc" "$seed") || exit
+
+# Print the line using sed(1)
sed -- "$ri"'!d' "$@"
diff --git a/bin/rnds b/bin/rnds
index 98851208..c5ffabe4 100755
--- a/bin/rnds
+++ b/bin/rnds
@@ -1,11 +1,22 @@
#!/bin/sh
# Try to get a low-quality random seed from a random device if possible
-[ "$#" -le 1 ] || exit 2
+
+# Sole optional argument is the bytes to read; 32 is the default
+count=${1:-32}
+
+# Try and find a random device to use; none of these are specified by POSIX
for dev in /dev/urandom /dev/arandom /dev/random '' ; do
[ -e "$dev" ] && break
done
+
+# Bail if we couldn't find a random device
[ -n "$dev" ] || exit 1
-count=${1:-32}
+
+# Read the bytes from the device
dd if="$dev" bs=1 count="$count" 2>/dev/null |
+
+# Run cksum(1) over the read random bytes
cksum |
+
+# cut(1) the cksum(1) output to only the first field, and print that to stdout
cut -d' ' -f1
diff --git a/bin/sls b/bin/sls
index df8625de..d3c67cc7 100755
--- a/bin/sls
+++ b/bin/sls
@@ -1,12 +1,20 @@
#!/bin/sh
+# Print hostnames from ssh_config(5) files, defaulting to the usual paths
+
+# If we weren't given a file explicitly, we'll try to read both /etc/ssh_config
+# and ~/.ssh_config in that order if they exist
if [ "$#" -eq 0 ] ; then
for cfg in /etc/ssh_config "$HOME"/.ssh/config ; do
[ -e "$cfg" ] || continue
set -- "$@" "$cfg"
done
fi
+
+# If we still have no files to read, bail out and warn the user
if [ "$#" -eq 0 ] ; then
printf >&2 'sls: ssh_config(5) paths not found, need argument\n'
exit 1
fi
+
+# Otherwise, we can run slsf(1) over the ones we did collect
slsf -- "$@"
diff --git a/bin/slsf b/bin/slsf
index c40e342a..6824ec13 100755
--- a/bin/slsf
+++ b/bin/slsf
@@ -1,4 +1,5 @@
#!/usr/bin/awk -f
+# Print the first non-glob "Host" name from each line of ssh_config(5) files
# Manage the processing flag (starts set in each file)
FNR == 1 || /### sls/ { sls = 1 }
diff --git a/bin/stbl b/bin/stbl
index 7b1b1d2c..940fc3bb 100755
--- a/bin/stbl
+++ b/bin/stbl
@@ -1,12 +1,19 @@
#!/bin/sh
# Strip a trailing blank line from the given files with ed(1)
+
+# Check arguments
if [ "$#" -eq 0 ] ; then
printf 2>&1 'stbl: Need a filename\n'
exit 2
fi
+
+# Iterate over arguments and apply the same ed(1) script to each of them
for fn ; do
- ed -s -- "$fn" <<'EOF'
+ ed -s -- "$fn" <<'EOF' || ex=1
$g/^ *$/d
w
EOF
done
+
+# If any of the ed(1) commands failed, we should exit with 1
+exit "${ex:-0}"
diff --git a/bin/stex b/bin/stex
index f4173a88..d20e8e5b 100755
--- a/bin/stex
+++ b/bin/stex
@@ -1,15 +1,29 @@
#!/bin/sh
-# Strip an extension from the given files
+# Strip an extension from the given filenames
+
+# Check args
if [ "$#" -lt 2 ] ; then
printf >&2 'Need an extension .ext and a filename\n'
exit 2
fi
-ex=0 ext=$1
+
+# Extension is first arg, shift it off
+ext=$1
shift
+
+# Iterate through the given files (remaining args)
for sn ; do
+
+ # Strip trailing slash if any and then extension
sn=${sn%/}
dn=${sn%"$ext"}
+
+ # Ignore this file if its name wouldn't change
[ "$sn" != "$dn" ] || continue
+
+ # Attempt a rename, flag an error if there was one
mv -- "$sn" "$dn" || ex=1
done
-exit "$ex"
+
+# Exit with 1 if there was any failed mv(1) run
+exit "${ex:-0}"
diff --git a/bin/stws b/bin/stws
index a955d022..f48ef76f 100755
--- a/bin/stws
+++ b/bin/stws
@@ -1,12 +1,19 @@
#!/bin/sh
# Strip trailing spaces on one or more files
+
+# Check arguments
if [ "$#" -eq 0 ] ; then
printf >&2 'tstf: Need a filename\n'
exit 2
fi
+
+# Iterate over arguments and apply the same ed(1) script to each of them
for fn ; do
- ed -s -- "$fn" <<'EOF'
+ ed -s -- "$fn" <<'EOF' || ex=1
g/ *$/ s/ *$//
w
EOF
done
+
+# If any of the ed(1) commands failed, we should exit with 1
+exit "${ex:-0}"
diff --git a/bin/sue b/bin/sue
index d585e088..64d566f7 100755
--- a/bin/sue
+++ b/bin/sue
@@ -1,8 +1,17 @@
#!/bin/sh
# Run sudoedit(8) with an appropriate user on a set of files
+
+# Blank out the user variable
user=
+
+# Iterate over the given files
for file ; do
+
+ # Get the file's owner, or bail
file_owner=$(stat -c %U -- "$file") || exit
+
+ # Check that this file has the same owner as all previously checked files,
+ # if any
case $user in
"$file_owner"|'')
user=$file_owner
@@ -13,4 +22,6 @@ for file ; do
;;
esac
done
+
+# Run sudoedit(8) as the user that owns all the files
sudoedit -u "$user" -- "$@"
diff --git a/bin/u2d b/bin/u2d
index 662876e3..505b3d04 100755
--- a/bin/u2d
+++ b/bin/u2d
@@ -1,14 +1,27 @@
#!/bin/sh
+# Convert UNIX line endings to DOS ones
+
+# Check arguments
if [ "$#" -eq 0 ] ; then
printf >&2 'u2d: Need a filename\n'
exit 2
fi
+
+# Put a carriage return into a variable for convenience
r=$(printf '\r')
+
+# Iterate over arguments and apply the same ed(1) script to each of them
for fn ; do
+
+ # Note the heredoc WORD is intentionally unquoted because we want to expand
+ # $r within it to get a literal carriage return; the escape characters
+ # prescribed for ed(1) by POSIX are very limited
ed -s -- "$fn" <<EOF || ex=1
g/[^$r]\$/ s/\$/$r/
g/^\$/ s/\$/$r/
w
EOF
done
+
+# If any of the ed(1) commands failed, we should exit with 1
exit "${ex:-0}"
diff --git a/bin/urlc b/bin/urlc
index b898b99c..63f075bf 100755
--- a/bin/urlc
+++ b/bin/urlc
@@ -25,7 +25,6 @@ list=$td/list head=$td/head body=$td/body
# Iterate through input; ignore leading/trailing whitespace
# shellcheck disable=SC2002
cat -- "${@:--}" >"$list"
-ex=0
while read -r url ; do
# Skip anything that doesn't start with HTTP
@@ -74,4 +73,4 @@ done <"$list"
wait
# Exit if any errors
-exit "$ex"
+exit "${ex:-0}"