From c8ab406749124d2e762ad5cf53963070113afd0f Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Wed, 5 Apr 2017 20:06:39 +1200 Subject: Apply runtime shebanging to POSIX shell --- .gitignore | 88 ++++++++++++++++++++++++++++++++++++++++++++- Makefile | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++----- README.markdown | 5 ++- bin/ap | 34 ------------------ bin/ap.sh | 33 +++++++++++++++++ bin/apf | 63 -------------------------------- bin/apf.sh | 62 ++++++++++++++++++++++++++++++++ bin/ax | 28 --------------- bin/ax.sh | 27 ++++++++++++++ bin/bcq | 4 --- bin/bcq.sh | 3 ++ bin/bel | 3 -- bin/bel.sh | 2 ++ bin/bl | 11 ------ bin/bl.sh | 10 ++++++ bin/bp | 3 -- bin/bp.sh | 2 ++ bin/br | 3 -- bin/br.sh | 2 ++ bin/ca | 3 -- bin/ca.sh | 2 ++ bin/cf | 25 ------------- bin/cf.sh | 24 +++++++++++++ bin/cfr | 25 ------------- bin/cfr.sh | 24 +++++++++++++ bin/chc | 31 ---------------- bin/chc.sh | 30 ++++++++++++++++ bin/chn | 70 ------------------------------------ bin/chn.sh | 69 +++++++++++++++++++++++++++++++++++ bin/clog | 10 ------ bin/clog.sh | 9 +++++ bin/clrd | 16 --------- bin/clrd.sh | 15 ++++++++ bin/clwr | 24 ------------- bin/clwr.sh | 23 ++++++++++++ bin/d2u | 26 -------------- bin/d2u.sh | 25 +++++++++++++ bin/dmp | 31 ---------------- bin/dmp.sh | 30 ++++++++++++++++ bin/dub | 32 ----------------- bin/dub.sh | 31 ++++++++++++++++ bin/edda | 34 ------------------ bin/edda.sh | 33 +++++++++++++++++ bin/eds | 51 -------------------------- bin/eds.sh | 50 ++++++++++++++++++++++++++ bin/exm | 13 ------- bin/exm.sh | 12 +++++++ bin/fgscr | 9 ----- bin/fgscr.sh | 8 +++++ bin/finc | 3 -- bin/finc.sh | 2 ++ bin/fnl | 21 ----------- bin/fnl.sh | 20 +++++++++++ bin/gms | 31 ---------------- bin/gms.sh | 30 ++++++++++++++++ bin/grc | 16 --------- bin/grc.sh | 15 ++++++++ bin/gscr | 29 --------------- bin/gscr.sh | 28 +++++++++++++++ bin/hurl | 11 ------ bin/hurl.sh | 10 ++++++ bin/igex | 34 ------------------ bin/igex.sh | 33 +++++++++++++++++ bin/isgr | 13 ------- bin/isgr.sh | 12 +++++++ bin/ix | 4 --- bin/ix.sh | 3 ++ bin/jfc | 14 -------- bin/jfc.sh | 13 +++++++ bin/jfcd | 23 ------------ bin/jfcd.sh | 22 ++++++++++++ bin/loc | 19 ---------- bin/loc.sh | 18 ++++++++++ bin/maybe | 24 ------------- bin/maybe.sh | 23 ++++++++++++ bin/mex | 53 --------------------------- bin/mex.sh | 52 +++++++++++++++++++++++++++ bin/mkcp | 18 ---------- bin/mkcp.sh | 17 +++++++++ bin/mkmv | 18 ---------- bin/mkmv.sh | 17 +++++++++ bin/mktd | 12 ------- bin/mktd.sh | 11 ++++++ bin/motd | 5 --- bin/motd.sh | 4 +++ bin/murl | 6 ---- bin/murl.sh | 5 +++ bin/osc | 92 ----------------------------------------------- bin/osc.sh | 91 ++++++++++++++++++++++++++++++++++++++++++++++ bin/pa | 4 --- bin/pa.sh | 3 ++ bin/paz | 4 --- bin/paz.sh | 3 ++ bin/pit | 17 --------- bin/pit.sh | 16 +++++++++ bin/plmu | 23 ------------ bin/plmu.sh | 22 ++++++++++++ bin/pp | 9 ----- bin/pp.sh | 8 +++++ bin/pph | 5 --- bin/pph.sh | 4 +++ bin/pwg | 7 ---- bin/pwg.sh | 6 ++++ bin/rfcf | 13 ------- bin/rfcf.sh | 12 +++++++ bin/rfcr | 19 ---------- bin/rfcr.sh | 18 ++++++++++ bin/rgl | 35 ------------------ bin/rgl.sh | 34 ++++++++++++++++++ bin/rnda | 20 ----------- bin/rnda.sh | 19 ++++++++++ bin/rndf | 18 ---------- bin/rndf.sh | 17 +++++++++ bin/rndl | 51 -------------------------- bin/rndl.sh | 50 ++++++++++++++++++++++++++ bin/rnds | 22 ------------ bin/rnds.sh | 21 +++++++++++ bin/shb | 27 -------------- bin/shb.sh | 26 ++++++++++++++ bin/slow | 4 --- bin/slow.sh | 3 ++ bin/sls | 20 ----------- bin/sls.sh | 19 ++++++++++ bin/sqs | 34 ------------------ bin/sqs.sh | 33 +++++++++++++++++ bin/sra | 8 ----- bin/sra.sh | 7 ++++ bin/sshi | 28 --------------- bin/sshi.sh | 27 ++++++++++++++ bin/sta | 8 ----- bin/sta.sh | 7 ++++ bin/stbl | 19 ---------- bin/stbl.sh | 18 ++++++++++ bin/stex | 39 -------------------- bin/stex.sh | 38 ++++++++++++++++++++ bin/stws | 19 ---------- bin/stws.sh | 18 ++++++++++ bin/sue | 27 -------------- bin/sue.sh | 26 ++++++++++++++ bin/supp | 4 --- bin/supp.sh | 3 ++ bin/swr | 65 --------------------------------- bin/swr.sh | 64 +++++++++++++++++++++++++++++++++ bin/td | 32 ----------------- bin/td.sh | 31 ++++++++++++++++ bin/tl | 29 --------------- bin/tl.sh | 28 +++++++++++++++ bin/tlcs | 94 ------------------------------------------------ bin/tlcs.sh | 93 +++++++++++++++++++++++++++++++++++++++++++++++ bin/tm | 18 ---------- bin/tm.sh | 17 +++++++++ bin/try | 78 ---------------------------------------- bin/try.sh | 77 +++++++++++++++++++++++++++++++++++++++ bin/u2d | 27 -------------- bin/u2d.sh | 26 ++++++++++++++ bin/umake | 11 ------ bin/umake.sh | 10 ++++++ bin/urlc | 77 --------------------------------------- bin/urlc.sh | 76 +++++++++++++++++++++++++++++++++++++++ bin/urlh | 30 ---------------- bin/urlh.sh | 29 +++++++++++++++ bin/urlmt | 9 ----- bin/urlmt.sh | 8 +++++ bin/vest | 7 ---- bin/vest.sh | 6 ++++ bin/vex | 14 -------- bin/vex.sh | 13 +++++++ bin/wro | 31 ---------------- bin/wro.sh | 30 ++++++++++++++++ bin/xgo | 79 ---------------------------------------- bin/xgo.sh | 78 ++++++++++++++++++++++++++++++++++++++++ bin/xgoc | 3 -- bin/xgoc.sh | 2 ++ bin/xrbg | 4 --- bin/xrbg.sh | 3 ++ games/aaf | 3 -- games/aaf.sh | 3 ++ games/dr | 36 ------------------- games/dr.sh | 36 +++++++++++++++++++ games/rndn | 43 ---------------------- games/rndn.sh | 43 ++++++++++++++++++++++ games/xyzzy | 6 ---- games/xyzzy.sh | 6 ++++ lint/bin | 11 +----- lint/games | 11 +----- 185 files changed, 2284 insertions(+), 2205 deletions(-) delete mode 100755 bin/ap create mode 100644 bin/ap.sh delete mode 100755 bin/apf create mode 100644 bin/apf.sh delete mode 100755 bin/ax create mode 100644 bin/ax.sh delete mode 100755 bin/bcq create mode 100644 bin/bcq.sh delete mode 100755 bin/bel create mode 100644 bin/bel.sh delete mode 100755 bin/bl create mode 100644 bin/bl.sh delete mode 100755 bin/bp create mode 100644 bin/bp.sh delete mode 100755 bin/br create mode 100644 bin/br.sh delete mode 100755 bin/ca create mode 100644 bin/ca.sh delete mode 100755 bin/cf create mode 100644 bin/cf.sh delete mode 100755 bin/cfr create mode 100644 bin/cfr.sh delete mode 100755 bin/chc create mode 100644 bin/chc.sh delete mode 100755 bin/chn create mode 100644 bin/chn.sh delete mode 100755 bin/clog create mode 100644 bin/clog.sh delete mode 100755 bin/clrd create mode 100644 bin/clrd.sh delete mode 100755 bin/clwr create mode 100644 bin/clwr.sh delete mode 100755 bin/d2u create mode 100644 bin/d2u.sh delete mode 100755 bin/dmp create mode 100644 bin/dmp.sh delete mode 100755 bin/dub create mode 100644 bin/dub.sh delete mode 100755 bin/edda create mode 100644 bin/edda.sh delete mode 100755 bin/eds create mode 100644 bin/eds.sh delete mode 100755 bin/exm create mode 100644 bin/exm.sh delete mode 100755 bin/fgscr create mode 100644 bin/fgscr.sh delete mode 100755 bin/finc create mode 100644 bin/finc.sh delete mode 100755 bin/fnl create mode 100644 bin/fnl.sh delete mode 100755 bin/gms create mode 100644 bin/gms.sh delete mode 100755 bin/grc create mode 100644 bin/grc.sh delete mode 100755 bin/gscr create mode 100644 bin/gscr.sh delete mode 100755 bin/hurl create mode 100644 bin/hurl.sh delete mode 100755 bin/igex create mode 100644 bin/igex.sh delete mode 100755 bin/isgr create mode 100644 bin/isgr.sh delete mode 100755 bin/ix create mode 100644 bin/ix.sh delete mode 100755 bin/jfc create mode 100644 bin/jfc.sh delete mode 100755 bin/jfcd create mode 100644 bin/jfcd.sh delete mode 100755 bin/loc create mode 100644 bin/loc.sh delete mode 100755 bin/maybe create mode 100644 bin/maybe.sh delete mode 100755 bin/mex create mode 100644 bin/mex.sh delete mode 100755 bin/mkcp create mode 100644 bin/mkcp.sh delete mode 100755 bin/mkmv create mode 100644 bin/mkmv.sh delete mode 100755 bin/mktd create mode 100644 bin/mktd.sh delete mode 100755 bin/motd create mode 100644 bin/motd.sh delete mode 100755 bin/murl create mode 100644 bin/murl.sh delete mode 100755 bin/osc create mode 100644 bin/osc.sh delete mode 100755 bin/pa create mode 100644 bin/pa.sh delete mode 100755 bin/paz create mode 100644 bin/paz.sh delete mode 100755 bin/pit create mode 100644 bin/pit.sh delete mode 100755 bin/plmu create mode 100644 bin/plmu.sh delete mode 100755 bin/pp create mode 100644 bin/pp.sh delete mode 100755 bin/pph create mode 100644 bin/pph.sh delete mode 100755 bin/pwg create mode 100644 bin/pwg.sh delete mode 100755 bin/rfcf create mode 100644 bin/rfcf.sh delete mode 100755 bin/rfcr create mode 100644 bin/rfcr.sh delete mode 100755 bin/rgl create mode 100644 bin/rgl.sh delete mode 100755 bin/rnda create mode 100644 bin/rnda.sh delete mode 100755 bin/rndf create mode 100644 bin/rndf.sh delete mode 100755 bin/rndl create mode 100644 bin/rndl.sh delete mode 100755 bin/rnds create mode 100644 bin/rnds.sh delete mode 100755 bin/shb create mode 100644 bin/shb.sh delete mode 100755 bin/slow create mode 100644 bin/slow.sh delete mode 100755 bin/sls create mode 100644 bin/sls.sh delete mode 100755 bin/sqs create mode 100644 bin/sqs.sh delete mode 100755 bin/sra create mode 100644 bin/sra.sh delete mode 100755 bin/sshi create mode 100644 bin/sshi.sh delete mode 100755 bin/sta create mode 100644 bin/sta.sh delete mode 100755 bin/stbl create mode 100644 bin/stbl.sh delete mode 100755 bin/stex create mode 100644 bin/stex.sh delete mode 100755 bin/stws create mode 100644 bin/stws.sh delete mode 100755 bin/sue create mode 100644 bin/sue.sh delete mode 100755 bin/supp create mode 100644 bin/supp.sh delete mode 100755 bin/swr create mode 100644 bin/swr.sh delete mode 100755 bin/td create mode 100644 bin/td.sh delete mode 100755 bin/tl create mode 100644 bin/tl.sh delete mode 100755 bin/tlcs create mode 100644 bin/tlcs.sh delete mode 100755 bin/tm create mode 100644 bin/tm.sh delete mode 100755 bin/try create mode 100644 bin/try.sh delete mode 100755 bin/u2d create mode 100644 bin/u2d.sh delete mode 100755 bin/umake create mode 100644 bin/umake.sh delete mode 100755 bin/urlc create mode 100644 bin/urlc.sh delete mode 100755 bin/urlh create mode 100644 bin/urlh.sh delete mode 100755 bin/urlmt create mode 100644 bin/urlmt.sh delete mode 100755 bin/vest create mode 100644 bin/vest.sh delete mode 100755 bin/vex create mode 100644 bin/vex.sh delete mode 100755 bin/wro create mode 100644 bin/wro.sh delete mode 100755 bin/xgo create mode 100644 bin/xgo.sh delete mode 100755 bin/xgoc create mode 100644 bin/xgoc.sh delete mode 100755 bin/xrbg create mode 100644 bin/xrbg.sh delete mode 100755 games/aaf create mode 100644 games/aaf.sh delete mode 100755 games/dr create mode 100644 games/dr.sh delete mode 100755 games/rndn create mode 100644 games/rndn.sh delete mode 100755 games/xyzzy create mode 100644 games/xyzzy.sh diff --git a/.gitignore b/.gitignore index 8ccf6b5f..ca6f199b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,117 @@ +bin/ap +bin/apf +bin/ax +bin/bcq +bin/bel +bin/bl +bin/bp +bin/br bin/brnl +bin/ca +bin/cf +bin/cfr +bin/chc +bin/chn +bin/clog +bin/clrd +bin/clwr bin/csmw +bin/d2u bin/ddup +bin/dmp +bin/dub +bin/edda +bin/eds +bin/exm +bin/fgscr +bin/finc +bin/fnl +bin/gms +bin/grc +bin/gscr bin/gwp -bin/jfp bin/han bin/hms bin/htdec bin/htenc bin/htref +bin/hurl +bin/igex +bin/isgr +bin/ix +bin/jfc +bin/jfcd +bin/jfp +bin/loc bin/max +bin/maybe bin/mean bin/med +bin/mex bin/mftl bin/min +bin/mkcp +bin/mkmv +bin/mktd bin/mode +bin/motd +bin/murl bin/nlbr bin/onl +bin/osc +bin/pa +bin/paz +bin/pit +bin/plmu +bin/pp +bin/pph +bin/pwg bin/quo +bin/rfcf +bin/rfcr bin/rfct +bin/rgl +bin/rnda +bin/rndf bin/rndi +bin/rndl +bin/rnds bin/sd2u bin/sec +bin/shb +bin/slow +bin/sls bin/slsf +bin/sqs +bin/sra +bin/sshi +bin/sta +bin/stbl +bin/stex +bin/stws bin/su2d +bin/sue +bin/supp +bin/swr +bin/td +bin/tl +bin/tlcs +bin/tm bin/tot +bin/try +bin/u2d +bin/umake bin/unf +bin/urlc +bin/urlh +bin/urlmt bin/uts +bin/vest +bin/vex +bin/wro +bin/xgo +bin/xgoc +bin/xrbg bin/xrq games/acq games/aesth diff --git a/Makefile b/Makefile index 24c3fab5..7dc69c2e 100644 --- a/Makefile +++ b/Makefile @@ -68,43 +68,133 @@ EMAIL = tom@sanctum.geek.nz KEY = 0xC14286EA77BB8872 SENDMAIL = msmtp -BINS = bin/brnl \ +BINS = bin/ap \ + bin/apf \ + bin/ax \ + bin/bcq \ + bin/bel \ + bin/bl \ + bin/bp \ + bin/br \ + bin/brnl \ + bin/ca \ + bin/cf \ + bin/cfr \ + bin/chc \ + bin/chn \ + bin/clog \ + bin/clrd \ + bin/clwr \ bin/csmw \ + bin/d2u \ bin/ddup \ + bin/dmp \ + bin/dub \ + bin/edda \ + bin/eds \ + bin/exm \ + bin/fgscr \ + bin/finc \ + bin/fnl \ + bin/gms \ + bin/grc \ + bin/gscr \ bin/gwp \ bin/han \ bin/hms \ bin/htdec \ bin/htenc \ bin/htref \ + bin/hurl \ + bin/igex \ + bin/isgr \ + bin/ix \ + bin/jfc \ + bin/jfcd \ bin/jfp \ + bin/loc \ bin/max \ + bin/maybe \ bin/mean \ bin/med \ + bin/mex \ bin/mftl \ bin/min \ + bin/mkcp \ + bin/mkmv \ + bin/mktd \ bin/mode \ + bin/motd \ + bin/murl \ bin/nlbr \ bin/onl \ + bin/osc \ + bin/pa \ + bin/paz \ + bin/pit \ + bin/plmu \ + bin/pp \ + bin/pph \ + bin/pwg \ bin/quo \ + bin/rfcf \ + bin/rfcr \ bin/rfct \ + bin/rgl \ + bin/rnda \ + bin/rndf \ bin/rndi \ + bin/rndl \ + bin/rnds \ bin/sd2u \ bin/sec \ + bin/shb \ + bin/slow \ + bin/sls \ bin/slsf \ + bin/sqs \ + bin/sra \ + bin/sshi \ + bin/sta \ + bin/stbl \ + bin/stex \ + bin/stws \ bin/su2d \ + bin/sue \ + bin/supp \ + bin/swr \ + bin/td \ + bin/tl \ + bin/tlcs \ + bin/tm \ bin/tot \ + bin/try \ + bin/u2d \ + bin/umake \ bin/unf \ + bin/urlc \ + bin/urlh \ + bin/urlmt \ bin/uts \ + bin/vest \ + bin/vex \ + bin/wro \ + bin/xgo \ + bin/xgoc \ + bin/xrbg \ bin/xrq -GAMES = games/acq \ +GAMES = games/aaf \ + games/acq \ games/aesth \ games/chkl \ + games/dr \ games/drakon \ games/kvlt \ + games/rndn \ games/rot13 \ games/strik \ + games/xyzzy \ games/zs all: $(BINS) git/gitconfig gnupg/gpg.conf @@ -147,19 +237,23 @@ tmux/tmux.conf: tmux/tmux.conf.m4 tmux/tmux.conf.m4 > $@ .awk: - bin/shb awk -f < $< > $@ + sh bin/shb.sh awk -f < $< > $@ chmod +x ./$@ .bash: - bin/shb bash < $< > $@ + sh bin/shb.sh bash < $< > $@ chmod +x ./$@ .pl: - bin/shb perl < $< > $@ + sh bin/shb.sh perl < $< > $@ chmod +x ./$@ .sed: - bin/shb sed -f < $< > $@ + sh bin/shb.sh sed -f < $< > $@ + chmod +x ./$@ + +.sh: + sh bin/shb.sh sh < $< > $@ chmod +x ./$@ install: install-bash \ @@ -403,10 +497,10 @@ lint: check \ lint-bash: lint/bash -lint-bin: $(BINS) +lint-bin: lint/bin -lint-games: $(GAMES) +lint-games: lint/games lint-ksh: diff --git a/README.markdown b/README.markdown index 43dddf0c..8fd19dff 100644 --- a/README.markdown +++ b/README.markdown @@ -15,7 +15,10 @@ Installation $ make -n install $ make install -For the default `all` target, you'll need `bash(1)`, `make(1)`, and `m4(1)`. +For the default `all` target, you'll need `make(1)`, `m4(1)`, and a +POSIX-fearing `sh(1)`. If you're on a system where `/bin/sh` is not a POSIX +shell, you may need to check you have e.g. `/usr/xpg4/bin` at the front of your +`$PATH` at build time. The installation `Makefile` will overwrite things standing in the way of its installed files without backing them up, so read the output of `make -n diff --git a/bin/ap b/bin/ap deleted file mode 100755 index b6ee36d4..00000000 --- a/bin/ap +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# Run a program with args read from standard input, prompted if from term -if [ "$#" -eq 0 ] ; then - printf >&2 'ap: Need at least one argument (command name)\n' - exit 2 -fi - -# Get the command name and shift it off -cmd=$1 -shift - -# Iterate through the remaining args; it's legal for there to be none, but in -# that case the user may as well just have invoked the command directly -for arg ; do - - # If this is the first iteration, clear the params away (we grabbed them in - # the for statement) - if [ -z "$reset" ] ; then - set -- - reset=1 - fi - - # If stdin is a terminal, prompt with the name of the argument - if [ -t 0 ] ; then - printf '%s: ' "$arg" - fi - - # Note that a whitespace or even empty argument is allowed - IFS= read -r val - set -- "$@" "$val" -done - -# Execute the command with the given parameters -exec "$cmd" "$@" diff --git a/bin/ap.sh b/bin/ap.sh new file mode 100644 index 00000000..1d6376cc --- /dev/null +++ b/bin/ap.sh @@ -0,0 +1,33 @@ +# Run a program with args read from standard input, prompted if from term +if [ "$#" -eq 0 ] ; then + printf >&2 'ap: Need at least one argument (command name)\n' + exit 2 +fi + +# Get the command name and shift it off +cmd=$1 +shift + +# Iterate through the remaining args; it's legal for there to be none, but in +# that case the user may as well just have invoked the command directly +for arg ; do + + # If this is the first iteration, clear the params away (we grabbed them in + # the for statement) + if [ -z "$reset" ] ; then + set -- + reset=1 + fi + + # If stdin is a terminal, prompt with the name of the argument + if [ -t 0 ] ; then + printf '%s: ' "$arg" + fi + + # Note that a whitespace or even empty argument is allowed + IFS= read -r val + set -- "$@" "$val" +done + +# Execute the command with the given parameters +exec "$cmd" "$@" diff --git a/bin/apf b/bin/apf deleted file mode 100755 index 39bc0720..00000000 --- a/bin/apf +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -# Prepend arguments from a file to the given arguments for a command -self=apf - -# Require at least two arguments -if [ "$#" -lt 2 ] ; then - printf >&2 '%s: Need an arguments file and a command\n' "$self" - exit 2 -fi - -# First argument is the file containing the null-delimited arguments -argf=$1 cmd=$2 -shift 2 - -# If there were arguments given on the command line, we need to be careful and -# prepend our ones first -if [ "$#" -gt 0 ] ; then - - # Iterate through any remaining arguments - for carg ; do - - # If this is the first command argument, then before we add it, we'll - # add all the ones from the file first if it exists - if [ -n "$argf" ] ; then - - # Reset the positional parameters - set -- - - # Put our file arguments in first before we continue with the loop - if [ -e "$argf" ] ; then - while IFS= read -r farg ; do - case $farg in - '#'*) continue ;; - *[![:space:]]*) ;; - *) continue ;; - esac - set -- "$@" "$farg" - done < "$argf" - fi - - # Unset the argfile so we don't repeat this bit - unset -v argf - fi - - # Stack the original invocation argument back onto the positional - # parameters - set -- "$@" "$carg" - done - -# If there weren't, we can just read the file and slap them in -elif [ -e "$argf" ] ; then - while IFS= read -r farg ; do - case $farg in - '#'*) continue ;; - *[![:space:]]*) ;; - *) continue ;; - esac - set -- "$@" "$farg" - done < "$argf" -fi - -# Run the command with the changed arguments -exec "$cmd" "$@" diff --git a/bin/apf.sh b/bin/apf.sh new file mode 100644 index 00000000..5e40e9b8 --- /dev/null +++ b/bin/apf.sh @@ -0,0 +1,62 @@ +# Prepend arguments from a file to the given arguments for a command +self=apf + +# Require at least two arguments +if [ "$#" -lt 2 ] ; then + printf >&2 '%s: Need an arguments file and a command\n' "$self" + exit 2 +fi + +# First argument is the file containing the null-delimited arguments +argf=$1 cmd=$2 +shift 2 + +# If there were arguments given on the command line, we need to be careful and +# prepend our ones first +if [ "$#" -gt 0 ] ; then + + # Iterate through any remaining arguments + for carg ; do + + # If this is the first command argument, then before we add it, we'll + # add all the ones from the file first if it exists + if [ -n "$argf" ] ; then + + # Reset the positional parameters + set -- + + # Put our file arguments in first before we continue with the loop + if [ -e "$argf" ] ; then + while IFS= read -r farg ; do + case $farg in + '#'*) continue ;; + *[![:space:]]*) ;; + *) continue ;; + esac + set -- "$@" "$farg" + done < "$argf" + fi + + # Unset the argfile so we don't repeat this bit + unset -v argf + fi + + # Stack the original invocation argument back onto the positional + # parameters + set -- "$@" "$carg" + done + +# If there weren't, we can just read the file and slap them in +elif [ -e "$argf" ] ; then + while IFS= read -r farg ; do + case $farg in + '#'*) continue ;; + *[![:space:]]*) ;; + *) continue ;; + esac + set -- "$@" "$farg" + done < "$argf" +fi + +# Run the command with the changed arguments +exec "$cmd" "$@" diff --git a/bin/ax b/bin/ax deleted file mode 100755 index 8dea72da..00000000 --- a/bin/ax +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# Evaluate an Awk expression given on the command line with an optional format - -# Count arguments -case $# in - - # If one argument, we assume format is %s - 1) form=%s expr=$1 ;; - - # If two arguments, first is format, second expression - 2) form=$1 expr=$2 ;; - - # Any other number of arguments is wrong - *) - printf >&2 'ax: Need an expression\n' - exit 2 - ;; -esac - -# Form program -prog=$(printf ' - BEGIN { - printf "%s\\n", %s - } -' "$form" "$expr") - -# Run program -awk "$prog" diff --git a/bin/ax.sh b/bin/ax.sh new file mode 100644 index 00000000..6ce1e9ea --- /dev/null +++ b/bin/ax.sh @@ -0,0 +1,27 @@ +# Evaluate an Awk expression given on the command line with an optional format + +# Count arguments +case $# in + + # If one argument, we assume format is %s + 1) form=%s expr=$1 ;; + + # If two arguments, first is format, second expression + 2) form=$1 expr=$2 ;; + + # Any other number of arguments is wrong + *) + printf >&2 'ax: Need an expression\n' + exit 2 + ;; +esac + +# Form program +prog=$(printf ' + BEGIN { + printf "%s\\n", %s + } +' "$form" "$expr") + +# Run program +awk "$prog" diff --git a/bin/bcq b/bin/bcq deleted file mode 100755 index 7b950b56..00000000 --- a/bin/bcq +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Fire up bc(1), hushing it if it looks like GNU -[ -e "$HOME"/.cache/bc/quiet ] && set -- --quiet "$@" -exec bc "$@" diff --git a/bin/bcq.sh b/bin/bcq.sh new file mode 100644 index 00000000..71a79666 --- /dev/null +++ b/bin/bcq.sh @@ -0,0 +1,3 @@ +# Fire up bc(1), hushing it if it looks like GNU +[ -e "$HOME"/.cache/bc/quiet ] && set -- --quiet "$@" +exec bc "$@" diff --git a/bin/bel b/bin/bel deleted file mode 100755 index c1c2ce1c..00000000 --- a/bin/bel +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Print a terminal bell -printf '\a' diff --git a/bin/bel.sh b/bin/bel.sh new file mode 100644 index 00000000..e87eceda --- /dev/null +++ b/bin/bel.sh @@ -0,0 +1,2 @@ +# Print a terminal bell +printf '\a' diff --git a/bin/bl b/bin/bl deleted file mode 100755 index b1831387..00000000 --- a/bin/bl +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Generate blank lines -if [ "$#" -ne 1 ] || [ "$1" -lt 0 ] ; then - printf >&2 'bl: Non-negative line count needed as sole argument\n' - exit 2 -fi -n=0 -while [ "$n" -lt "${1:-0}" ] ; do - printf '\n' - n=$((n+1)) -done diff --git a/bin/bl.sh b/bin/bl.sh new file mode 100644 index 00000000..6dd3d687 --- /dev/null +++ b/bin/bl.sh @@ -0,0 +1,10 @@ +# Generate blank lines +if [ "$#" -ne 1 ] || [ "$1" -lt 0 ] ; then + printf >&2 'bl: Non-negative line count needed as sole argument\n' + exit 2 +fi +n=0 +while [ "$n" -lt "${1:-0}" ] ; do + printf '\n' + n=$((n+1)) +done diff --git a/bin/bp b/bin/bp deleted file mode 100755 index 6b78fbbc..00000000 --- a/bin/bp +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Read an URL and then browse to it, saving the annoyance of quoting URLs -ap br URL diff --git a/bin/bp.sh b/bin/bp.sh new file mode 100644 index 00000000..34065ca3 --- /dev/null +++ b/bin/bp.sh @@ -0,0 +1,2 @@ +# Read an URL and then browse to it, saving the annoyance of quoting URLs +ap br URL diff --git a/bin/br b/bin/br deleted file mode 100755 index 399c6038..00000000 --- a/bin/br +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Just launch $BROWSER with any given arguments -exec "$BROWSER" "$@" diff --git a/bin/br.sh b/bin/br.sh new file mode 100644 index 00000000..72507528 --- /dev/null +++ b/bin/br.sh @@ -0,0 +1,2 @@ +# Just launch $BROWSER with any given arguments +exec "$BROWSER" "$@" diff --git a/bin/ca b/bin/ca deleted file mode 100755 index 836299ce..00000000 --- a/bin/ca +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Print a count of the number of arguments -printf '%u\n' "$#" diff --git a/bin/ca.sh b/bin/ca.sh new file mode 100644 index 00000000..1d6333ad --- /dev/null +++ b/bin/ca.sh @@ -0,0 +1,2 @@ +# Print a count of the number of arguments +printf '%u\n' "$#" diff --git a/bin/cf b/bin/cf deleted file mode 100755 index 347481f1..00000000 --- a/bin/cf +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# Count entries in a given set of directories - -# Iterate over remaining non-option arguments (directories); default to current -# directory if none given -for dir in "${@:-.}" ; do - - # Attempt to count the files in a subshell - if count=$( - cd -- "$dir" || exit - find . ! -name . -prune -exec printf %.sx {} + | - wc -c - ) ; then - - # If it worked, print the count - printf '%u\t%s\n' "$count" "$dir" - else - - # If not, set the error flag and continue - ex=1 - fi -done - -# Exit non-zero if a non-directory was given as an argument -exit "${ex:-0}" diff --git a/bin/cf.sh b/bin/cf.sh new file mode 100644 index 00000000..ea3a2887 --- /dev/null +++ b/bin/cf.sh @@ -0,0 +1,24 @@ +# Count entries in a given set of directories + +# Iterate over remaining non-option arguments (directories); default to current +# directory if none given +for dir in "${@:-.}" ; do + + # Attempt to count the files in a subshell + if count=$( + cd -- "$dir" || exit + find . ! -name . -prune -exec printf %.sx {} + | + wc -c + ) ; then + + # If it worked, print the count + printf '%u\t%s\n' "$count" "$dir" + else + + # If not, set the error flag and continue + ex=1 + fi +done + +# Exit non-zero if a non-directory was given as an argument +exit "${ex:-0}" diff --git a/bin/cfr b/bin/cfr deleted file mode 100755 index d49ab3d9..00000000 --- a/bin/cfr +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# Count entries in a given set of directories - -# Iterate over remaining non-option arguments (directories); default to current -# directory if none given -for dir in "${@:-.}" ; do - - # Attempt to count the files in a subshell - if count=$( - cd -- "$dir" || exit - find . ! -name . -exec printf %.sx {} + | - wc -c - ) ; then - - # If it worked, print the count - printf '%u\t%s\n' "$count" "$dir" - else - - # If not, set the error flag and continue - ex=1 - fi -done - -# Exit non-zero if a non-directory was given as an argument -exit "${ex:-0}" diff --git a/bin/cfr.sh b/bin/cfr.sh new file mode 100644 index 00000000..9d13785c --- /dev/null +++ b/bin/cfr.sh @@ -0,0 +1,24 @@ +# Count entries in a given set of directories + +# Iterate over remaining non-option arguments (directories); default to current +# directory if none given +for dir in "${@:-.}" ; do + + # Attempt to count the files in a subshell + if count=$( + cd -- "$dir" || exit + find . ! -name . -exec printf %.sx {} + | + wc -c + ) ; then + + # If it worked, print the count + printf '%u\t%s\n' "$count" "$dir" + else + + # If not, set the error flag and continue + ex=1 + fi +done + +# Exit non-zero if a non-directory was given as an argument +exit "${ex:-0}" diff --git a/bin/chc b/bin/chc deleted file mode 100755 index b1e4000d..00000000 --- a/bin/chc +++ /dev/null @@ -1,31 +0,0 @@ -#!/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/bin/chc.sh b/bin/chc.sh new file mode 100644 index 00000000..8b15317c --- /dev/null +++ b/bin/chc.sh @@ -0,0 +1,30 @@ +# 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/bin/chn b/bin/chn deleted file mode 100755 index 46a8a27a..00000000 --- a/bin/chn +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh -# Repeat a command to filter input several times -self=chn - -# Check arguments. -if [ "$#" -lt 2 ] ; then - printf >&2 '%s: Need a count and a program name\n' "$self" - exit 2 -fi - -# Shift off the repetition count. -c=$1 -shift - -# Check the repetition count looks sane. Zero is fine! -if [ "$c" -lt 0 ] ; then - printf >&2 '%s: Nonsensical negative count\n' "$self" - exit 2 -fi - -# If the count is zero, just run the input straight through! -if [ "$c" -eq 0 ] ; then - cat - exit -fi - -# 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 - -# Define and create input and output files -if=$td/if of=$td/of -touch -- "$if" "$of" - -# Iterate through the count -while [ "${n=1}" -le "$c" ] ; do - - # Start a subshell so we can deal with FDs cleanly - ( - # If this isn't the first iteration, our input comes from $if - [ "$n" -eq 1 ] || - exec <"$if" - - # If this isn't the last iteration, our output goes to $of - [ "$n" -eq "$c" ] || - exec >"$of" - - # Run the command with the descriptors above; if the command fails, the - # subshell will exit, which will in turn exit the program - "$@" - ) || exit - - # Copy the output file over the input one - cp -- "$of" "$if" - - # Increment the counter for the next while loop run - n=$((n+1)) -done diff --git a/bin/chn.sh b/bin/chn.sh new file mode 100644 index 00000000..9103dd07 --- /dev/null +++ b/bin/chn.sh @@ -0,0 +1,69 @@ +# Repeat a command to filter input several times +self=chn + +# Check arguments. +if [ "$#" -lt 2 ] ; then + printf >&2 '%s: Need a count and a program name\n' "$self" + exit 2 +fi + +# Shift off the repetition count. +c=$1 +shift + +# Check the repetition count looks sane. Zero is fine! +if [ "$c" -lt 0 ] ; then + printf >&2 '%s: Nonsensical negative count\n' "$self" + exit 2 +fi + +# If the count is zero, just run the input straight through! +if [ "$c" -eq 0 ] ; then + cat + exit +fi + +# 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 + +# Define and create input and output files +if=$td/if of=$td/of +touch -- "$if" "$of" + +# Iterate through the count +while [ "${n=1}" -le "$c" ] ; do + + # Start a subshell so we can deal with FDs cleanly + ( + # If this isn't the first iteration, our input comes from $if + [ "$n" -eq 1 ] || + exec <"$if" + + # If this isn't the last iteration, our output goes to $of + [ "$n" -eq "$c" ] || + exec >"$of" + + # Run the command with the descriptors above; if the command fails, the + # subshell will exit, which will in turn exit the program + "$@" + ) || exit + + # Copy the output file over the input one + cp -- "$of" "$if" + + # Increment the counter for the next while loop run + n=$((n+1)) +done diff --git a/bin/clog b/bin/clog deleted file mode 100755 index 037f24c7..00000000 --- a/bin/clog +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# Record a timestamped message to a logfile, defaulting to ~/.clog -self=clog -command -v rlwrap >/dev/null 2>&1 && - set -- rlwrap -C "$self" "$@" -{ - date - "$@" cat - - printf '%s\n' -- -} >>"${CLOG:-"$HOME"/.clog}" diff --git a/bin/clog.sh b/bin/clog.sh new file mode 100644 index 00000000..0964ce90 --- /dev/null +++ b/bin/clog.sh @@ -0,0 +1,9 @@ +# Record a timestamped message to a logfile, defaulting to ~/.clog +self=clog +command -v rlwrap >/dev/null 2>&1 && + set -- rlwrap -C "$self" "$@" +{ + date + "$@" cat - + printf '%s\n' -- +} >>"${CLOG:-"$HOME"/.clog}" diff --git a/bin/clrd b/bin/clrd deleted file mode 100755 index 0b460671..00000000 --- a/bin/clrd +++ /dev/null @@ -1,16 +0,0 @@ -#!/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 -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/clrd.sh b/bin/clrd.sh new file mode 100644 index 00000000..bf239033 --- /dev/null +++ b/bin/clrd.sh @@ -0,0 +1,15 @@ +# 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 +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/clwr b/bin/clwr deleted file mode 100755 index dc045e9d..00000000 --- a/bin/clwr +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Write lines of terminal input into a file, clearing in between each one -self=clwr - -# Check our inputs for sanity -if [ "$#" -ne 1 ] ; then - printf >&2 '%s: Need output file\n' "$self" - exit 2 -elif ! [ -t 0 ] ; then - printf >&2 '%s: stdin not a terminal\n' "$self" - exit 2 -elif ! [ -t 1 ] ; then - printf >&2 '%s: stdout not a terminal\n' "$self" - exit 2 -fi - -# Open a file descriptor onto the output file to save on open(2)/close(2) -# system calls -exec 3>"$1" || exit - -# Start looping through clearing and accepting lines -while { tput clear && IFS= read -r line ; } ; do - printf '%s\n' "$line" >&3 -done diff --git a/bin/clwr.sh b/bin/clwr.sh new file mode 100644 index 00000000..897c1a01 --- /dev/null +++ b/bin/clwr.sh @@ -0,0 +1,23 @@ +# Write lines of terminal input into a file, clearing in between each one +self=clwr + +# Check our inputs for sanity +if [ "$#" -ne 1 ] ; then + printf >&2 '%s: Need output file\n' "$self" + exit 2 +elif ! [ -t 0 ] ; then + printf >&2 '%s: stdin not a terminal\n' "$self" + exit 2 +elif ! [ -t 1 ] ; then + printf >&2 '%s: stdout not a terminal\n' "$self" + exit 2 +fi + +# Open a file descriptor onto the output file to save on open(2)/close(2) +# system calls +exec 3>"$1" || exit + +# Start looping through clearing and accepting lines +while { tput clear && IFS= read -r line ; } ; do + printf '%s\n' "$line" >&3 +done diff --git a/bin/d2u b/bin/d2u deleted file mode 100755 index 6fe362b7..00000000 --- a/bin/d2u +++ /dev/null @@ -1,26 +0,0 @@ -#!/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" <&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" </dev/null >&2 ; then - notify-send "$(printf '%s in clipboard' "$pw")" -fi diff --git a/bin/dmp.sh b/bin/dmp.sh new file mode 100644 index 00000000..ea79214f --- /dev/null +++ b/bin/dmp.sh @@ -0,0 +1,30 @@ + +# Get the password store directory, bail if we can't +pwsd=${PASSWORD_STORE_DIR:-"$HOME"/.password-store} +pwsd=${pwsd%/} +[ -n "$pwsd" ] || exit + +# Get the password; get all the names from find(1) +# shellcheck disable=SC2016 +pw=$( + cd -- "$pwsd" || exit + # Get all the names from find(1) + find ./ -name \*.gpg | + # Sort them + sort | + # Strip the leading directory and the trailing .gpg + sed 's_^\./__;s_\.gpg$__' | + # Use dmenu(1) to prompt the user to select one + dmenu +) || exit + +# Bail if we don't have a password +[ -n "$pw" ] || exit + +# Pump the first line of the password into the clipboard +pass show "$pw" | sed 1q | xsel -ib || exit + +# If we have notify-send(1), alert that the password has been copied +if command -v notify-send >/dev/null >&2 ; then + notify-send "$(printf '%s in clipboard' "$pw")" +fi diff --git a/bin/dub b/bin/dub deleted file mode 100755 index 36d787a4..00000000 --- a/bin/dub +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# List the biggest files in a directory - -# 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 -k1,1nr | - -# Limit the output to the given number of lines -sed "$lines"q diff --git a/bin/dub.sh b/bin/dub.sh new file mode 100644 index 00000000..f42c5ac9 --- /dev/null +++ b/bin/dub.sh @@ -0,0 +1,31 @@ +# List the biggest files in a directory + +# 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 -k1,1nr | + +# Limit the output to the given number of lines +sed "$lines"q diff --git a/bin/edda b/bin/edda deleted file mode 100755 index 6af88a5f..00000000 --- a/bin/edda +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# Run ed(1) over multiple files, duplicating stdin. -self=edda - -# Need at least one file -if [ "$#" -eq 0 ] ; then - printf >&2 'edda: Need at least one file\n' - exit 2 -fi - -# 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 - -# Duplicate stdin into a file -script=$td/script -cat >"$script" || exit - -# Run ed(1) over each file with the stdin given -for file ; do - ed -- "$file" <"$script" -done diff --git a/bin/edda.sh b/bin/edda.sh new file mode 100644 index 00000000..b1d7b27a --- /dev/null +++ b/bin/edda.sh @@ -0,0 +1,33 @@ +# Run ed(1) over multiple files, duplicating stdin. +self=edda + +# Need at least one file +if [ "$#" -eq 0 ] ; then + printf >&2 'edda: Need at least one file\n' + exit 2 +fi + +# 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 + +# Duplicate stdin into a file +script=$td/script +cat >"$script" || exit + +# Run ed(1) over each file with the stdin given +for file ; do + ed -- "$file" <"$script" +done diff --git a/bin/eds b/bin/eds deleted file mode 100755 index e39215d4..00000000 --- a/bin/eds +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# Create and edit executable scripts in a directory EDSPATH (defaults to ~/.local/bin) - -# Need at least one script name -if [ "$#" -eq 0 ] ; then - printf >&2 'eds: Need at least one script name\n' - exit 2 -fi - -# Create the script directory if it doesn't exist yet -ep=${EDSPATH:-$HOME/.local/bin} -if ! [ -d "$ep" ] ; then - mkdir -p -- "$ep" || exit -fi - -# Warn if that's not in $PATH -case :$PATH: in - *:"$ep":*) ;; - *) - printf >&2 'eds: warning: %s not in PATH\n' "$ep" - ;; -esac - -# Prepend the path to each of the names given if they don't look like options -for arg ; do - [ -n "$reset" ] || set -- && reset=1 - case $arg in - --) - optend=1 - set -- "$@" "$arg" - continue - ;; - -*) - if [ -z "$optend" ] ; then - set -- "$@" "$arg" - continue - fi - ;; - esac - optend=1 - set -- "$@" "$ep"/"$arg" -done - -# Run the editor over the arguments -"${VISUAL:-"${EDITOR:-ed}"}" "$@" - -# Make any created scripts executable if they now appear to be files -for script ; do - [ -f "$script" ] || continue - chmod +x -- "$script" -done diff --git a/bin/eds.sh b/bin/eds.sh new file mode 100644 index 00000000..c85069c6 --- /dev/null +++ b/bin/eds.sh @@ -0,0 +1,50 @@ +# Create and edit executable scripts in a directory EDSPATH (defaults to ~/.local/bin) + +# Need at least one script name +if [ "$#" -eq 0 ] ; then + printf >&2 'eds: Need at least one script name\n' + exit 2 +fi + +# Create the script directory if it doesn't exist yet +ep=${EDSPATH:-$HOME/.local/bin} +if ! [ -d "$ep" ] ; then + mkdir -p -- "$ep" || exit +fi + +# Warn if that's not in $PATH +case :$PATH: in + *:"$ep":*) ;; + *) + printf >&2 'eds: warning: %s not in PATH\n' "$ep" + ;; +esac + +# Prepend the path to each of the names given if they don't look like options +for arg ; do + [ -n "$reset" ] || set -- && reset=1 + case $arg in + --) + optend=1 + set -- "$@" "$arg" + continue + ;; + -*) + if [ -z "$optend" ] ; then + set -- "$@" "$arg" + continue + fi + ;; + esac + optend=1 + set -- "$@" "$ep"/"$arg" +done + +# Run the editor over the arguments +"${VISUAL:-"${EDITOR:-ed}"}" "$@" + +# Make any created scripts executable if they now appear to be files +for script ; do + [ -f "$script" ] || continue + chmod +x -- "$script" +done diff --git a/bin/exm b/bin/exm deleted file mode 100755 index f1afa17a..00000000 --- a/bin/exm +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# Prevent Vim's ex(1) implementation from clearing the screen -if [ -t 0 ] ; then - ver=$(ex --version 2>/dev/null | awk 'NR==1{print $1;exit}') - case $ver in - # Lie to Vim; tell it it's a dumb terminal, and that its required "cm" - # feature is invoked with a carriage return. - VIM) - cmd=$(printf 'set t_cm=\r|') - set -- -T dumb --cmd "${cmd%|}" "$@" ;; - esac -fi -exec ex "$@" diff --git a/bin/exm.sh b/bin/exm.sh new file mode 100644 index 00000000..25e3006f --- /dev/null +++ b/bin/exm.sh @@ -0,0 +1,12 @@ +# Prevent Vim's ex(1) implementation from clearing the screen +if [ -t 0 ] ; then + ver=$(ex --version 2>/dev/null | awk 'NR==1{print $1;exit}') + case $ver in + # Lie to Vim; tell it it's a dumb terminal, and that its required "cm" + # feature is invoked with a carriage return. + VIM) + cmd=$(printf 'set t_cm=\r|') + set -- -T dumb --cmd "${cmd%|}" "$@" ;; + esac +fi +exec ex "$@" diff --git a/bin/fgscr b/bin/fgscr deleted file mode 100755 index 7d5ff4c5..00000000 --- a/bin/fgscr +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Find all the Git repositories in a directory and scrub them all - -# Check we have gscr(1df) first -command -v gscr >/dev/null 2>&1 || exit - -# Look for any dir named .git in the given (default current) dir and run -# gscr(1df) on it -find "${@:-.}" -name '*.git' -type d -exec gscr {} \; diff --git a/bin/fgscr.sh b/bin/fgscr.sh new file mode 100644 index 00000000..137e0dd8 --- /dev/null +++ b/bin/fgscr.sh @@ -0,0 +1,8 @@ +# Find all the Git repositories in a directory and scrub them all + +# Check we have gscr(1df) first +command -v gscr >/dev/null 2>&1 || exit + +# Look for any dir named .git in the given (default current) dir and run +# gscr(1df) on it +find "${@:-.}" -name '*.git' -type d -exec gscr {} \; diff --git a/bin/finc b/bin/finc deleted file mode 100755 index 109f02b3..00000000 --- a/bin/finc +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Count the number of entries from a find(1) condition -find "${@:-.}" -exec printf .%sx {} + | wc -c diff --git a/bin/finc.sh b/bin/finc.sh new file mode 100644 index 00000000..2bbb9ae8 --- /dev/null +++ b/bin/finc.sh @@ -0,0 +1,2 @@ +# Count the number of entries from a find(1) condition +find "${@:-.}" -exec printf .%sx {} + | wc -c diff --git a/bin/fnl b/bin/fnl deleted file mode 100755 index 6969665b..00000000 --- a/bin/fnl +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# Run a command and save its output and error to temporary files - -# Check we have at least one argument -if [ "$#" -eq 0 ] ; then - printf >&2 'fnl: Command needed\n' - return 2 -fi - -# Create a temporary directory; note that we *don't* clean it up on exit -dir=$(mktd fnl) || exit - -# Run the command; keep its exit status -{ "$@" ; } >"$dir"/stdout 2>"$dir"/stderr -ret=$? - -# Run wc(1) on each of the files -wc -- "$dir"/* - -# Exit with the wrapped command's exit status -exit "$ret" diff --git a/bin/fnl.sh b/bin/fnl.sh new file mode 100644 index 00000000..8d771adb --- /dev/null +++ b/bin/fnl.sh @@ -0,0 +1,20 @@ +# Run a command and save its output and error to temporary files + +# Check we have at least one argument +if [ "$#" -eq 0 ] ; then + printf >&2 'fnl: Command needed\n' + return 2 +fi + +# Create a temporary directory; note that we *don't* clean it up on exit +dir=$(mktd fnl) || exit + +# Run the command; keep its exit status +{ "$@" ; } >"$dir"/stdout 2>"$dir"/stderr +ret=$? + +# Run wc(1) on each of the files +wc -- "$dir"/* + +# Exit with the wrapped command's exit status +exit "$ret" diff --git a/bin/gms b/bin/gms deleted file mode 100755 index 01cdaa2f..00000000 --- a/bin/gms +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# Run getmail(1) over every getmailrc.* file in ~/.getmail - -# Trap to remove whatever's set in lockdir if we're killed -lockdir= -cleanup() { - [ -n "$lockdir" ] && rm -fr -- "$lockdir" - 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 - -# Don't trust the environment $UID, use id(1) instead -uid=$(id -u) || exit - -# Iterate through the getmailrc.* files in $GETMAIL if defined, or -# $HOME/.getmail if not -for rcfile in "${GETMAIL:-"$HOME"/.getmail}"/getmailrc.* ; do ( - lockdir=${TMPDIR:-/tmp}/getmail.$uid.${rcfile##*/}.lock - mkdir -m 0700 -- "$lockdir" 2>/dev/null || exit - try -n 3 -s 15 getmail --rcfile "$rcfile" "$@" - rm -fr -- "$lockdir" && lockdir= -) & done - -# Wait for all of the enqueued tasks to finish -wait diff --git a/bin/gms.sh b/bin/gms.sh new file mode 100644 index 00000000..b77da6fa --- /dev/null +++ b/bin/gms.sh @@ -0,0 +1,30 @@ +# Run getmail(1) over every getmailrc.* file in ~/.getmail + +# Trap to remove whatever's set in lockdir if we're killed +lockdir= +cleanup() { + [ -n "$lockdir" ] && rm -fr -- "$lockdir" + 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 + +# Don't trust the environment $UID, use id(1) instead +uid=$(id -u) || exit + +# Iterate through the getmailrc.* files in $GETMAIL if defined, or +# $HOME/.getmail if not +for rcfile in "${GETMAIL:-"$HOME"/.getmail}"/getmailrc.* ; do ( + lockdir=${TMPDIR:-/tmp}/getmail.$uid.${rcfile##*/}.lock + mkdir -m 0700 -- "$lockdir" 2>/dev/null || exit + try -n 3 -s 15 getmail --rcfile "$rcfile" "$@" + rm -fr -- "$lockdir" && lockdir= +) & done + +# Wait for all of the enqueued tasks to finish +wait diff --git a/bin/grc b/bin/grc deleted file mode 100755 index 0db91afa..00000000 --- a/bin/grc +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -# 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 - -# 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/grc.sh b/bin/grc.sh new file mode 100644 index 00000000..184baf8e --- /dev/null +++ b/bin/grc.sh @@ -0,0 +1,15 @@ +# 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 + +# 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 deleted file mode 100755 index cac969fe..00000000 --- a/bin/gscr +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# 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 - ;; - *) - 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/gscr.sh b/bin/gscr.sh new file mode 100644 index 00000000..2fbee05a --- /dev/null +++ b/bin/gscr.sh @@ -0,0 +1,28 @@ +# 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 + ;; + *) + 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 deleted file mode 100755 index 16ea48f8..00000000 --- a/bin/hurl +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Extract URLs from an HTML document or documents - -# Input is either stdin or the given arguments concatenated -cat -- "${@:--}" | - -# Pipe through pup to get all the href links -pup -p 'a attr{href}' | - -# Sort them uniquely -sort | uniq diff --git a/bin/hurl.sh b/bin/hurl.sh new file mode 100644 index 00000000..0680c5ce --- /dev/null +++ b/bin/hurl.sh @@ -0,0 +1,10 @@ +# Extract URLs from an HTML document or documents + +# Input is either stdin or the given arguments concatenated +cat -- "${@:--}" | + +# 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 deleted file mode 100755 index c514006d..00000000 --- a/bin/igex +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# 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/igex.sh b/bin/igex.sh new file mode 100644 index 00000000..09f1206f --- /dev/null +++ b/bin/igex.sh @@ -0,0 +1,33 @@ +# 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 deleted file mode 100755 index 029b5352..00000000 --- a/bin/isgr +++ /dev/null @@ -1,13 +0,0 @@ -#!/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 diff --git a/bin/isgr.sh b/bin/isgr.sh new file mode 100644 index 00000000..9d3e97a8 --- /dev/null +++ b/bin/isgr.sh @@ -0,0 +1,12 @@ +# 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 diff --git a/bin/ix b/bin/ix deleted file mode 100755 index 45c1f860..00000000 --- a/bin/ix +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Convenience script for posting to ix.io pastebin -cat -- "${@:--}" | -curl -F 'f:1=<-' http://ix.io/ diff --git a/bin/ix.sh b/bin/ix.sh new file mode 100644 index 00000000..cffc186c --- /dev/null +++ b/bin/ix.sh @@ -0,0 +1,3 @@ +# Convenience script for posting to ix.io pastebin +cat -- "${@:--}" | +curl -F 'f:1=<-' http://ix.io/ diff --git a/bin/jfc b/bin/jfc deleted file mode 100755 index 33d0fe5d..00000000 --- a/bin/jfc +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# 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 - -# Quietly commit with a stock message and use its exit value as ours -git commit --message 'Committed by jfc(1df)' --quiet diff --git a/bin/jfc.sh b/bin/jfc.sh new file mode 100644 index 00000000..3d155aca --- /dev/null +++ b/bin/jfc.sh @@ -0,0 +1,13 @@ +# 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 + +# Quietly commit with a stock message and use its exit value as ours +git commit --message 'Committed by jfc(1df)' --quiet diff --git a/bin/jfcd b/bin/jfcd deleted file mode 100755 index 8bd54e3b..00000000 --- a/bin/jfcd +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# Watch a directory for changes and commit them with jfc(1d) if there are any; -# requires inotifywait(1) -self=jfcd - -# Function wrapper around inotifywait(1) -inw() { - inotifywait \ - @./.git \ - -e create -e delete -e modify -e move \ - --recursive \ - --syslog \ - . | - logger --tag "$self" -} - -# Directory to check is first and only argument; defaults to current directory -cd -- "${1:-.}" || exit - -# Run a while loop over inotifywait(1) calls, running jfc(1d) on the working -# directory -while inw ; do jfc ; done diff --git a/bin/jfcd.sh b/bin/jfcd.sh new file mode 100644 index 00000000..bf059883 --- /dev/null +++ b/bin/jfcd.sh @@ -0,0 +1,22 @@ + +# Watch a directory for changes and commit them with jfc(1d) if there are any; +# requires inotifywait(1) +self=jfcd + +# Function wrapper around inotifywait(1) +inw() { + inotifywait \ + @./.git \ + -e create -e delete -e modify -e move \ + --recursive \ + --syslog \ + . | + logger --tag "$self" +} + +# Directory to check is first and only argument; defaults to current directory +cd -- "${1:-.}" || exit + +# Run a while loop over inotifywait(1) calls, running jfc(1d) on the working +# directory +while inw ; do jfc ; done diff --git a/bin/loc b/bin/loc deleted file mode 100755 index d92dc886..00000000 --- a/bin/loc +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# Convenience find(1) wrapper for path substrings - -# Require at least one search term -if [ "$#" -eq 0 ] ; then - printf >&2 'loc: Need a search term\n' - exit 2 -fi - -# Iterate through each search term and run an appropriate find(1) command -for pat ; do - - # Skip dotfiles, dotdirs, and symbolic links; print anything that matches - # the term as a substring (and stop iterating through it) - find . \ - -name .\* ! -name . -prune -o \ - -type l -prune -o \ - -name \*"$pat"\* -prune -print -done diff --git a/bin/loc.sh b/bin/loc.sh new file mode 100644 index 00000000..995c6932 --- /dev/null +++ b/bin/loc.sh @@ -0,0 +1,18 @@ +# Convenience find(1) wrapper for path substrings + +# Require at least one search term +if [ "$#" -eq 0 ] ; then + printf >&2 'loc: Need a search term\n' + exit 2 +fi + +# Iterate through each search term and run an appropriate find(1) command +for pat ; do + + # Skip dotfiles, dotdirs, and symbolic links; print anything that matches + # the term as a substring (and stop iterating through it) + find . \ + -name .\* ! -name . -prune -o \ + -type l -prune -o \ + -name \*"$pat"\* -prune -print +done diff --git a/bin/maybe b/bin/maybe deleted file mode 100755 index a2de17dd..00000000 --- a/bin/maybe +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Exit with success or failure with a given probability -self=maybe - -# Figure out numerator and denominator from arguments -case $# in - 0) num=1 den=2 ;; - 1) num=1 den=$1 ;; - 2) num=$1 den=$2 ;; - *) - printf >&2 '%s: Unexpected arguments\n' "$self" - exit 2 - ;; -esac - -# Numerator must be zero or greater, denominator must be 1 or greater -if [ "$((num >= 0 || den >= 1))" -ne 1 ] ; then - printf >&2 '%s: Illegal numerator/denominator %s\n' "$self" "$num" - exit 2 -fi - -# Perform the test; that's our exit value -seed=$(rnds) -test "$(rndi 1 "$den" "$seed")" -le "$num" diff --git a/bin/maybe.sh b/bin/maybe.sh new file mode 100644 index 00000000..6e5c8658 --- /dev/null +++ b/bin/maybe.sh @@ -0,0 +1,23 @@ +# Exit with success or failure with a given probability +self=maybe + +# Figure out numerator and denominator from arguments +case $# in + 0) num=1 den=2 ;; + 1) num=1 den=$1 ;; + 2) num=$1 den=$2 ;; + *) + printf >&2 '%s: Unexpected arguments\n' "$self" + exit 2 + ;; +esac + +# Numerator must be zero or greater, denominator must be 1 or greater +if [ "$((num >= 0 || den >= 1))" -ne 1 ] ; then + printf >&2 '%s: Illegal numerator/denominator %s\n' "$self" "$num" + exit 2 +fi + +# Perform the test; that's our exit value +seed=$(rnds) +test "$(rndi 1 "$den" "$seed")" -le "$num" diff --git a/bin/mex b/bin/mex deleted file mode 100755 index 005149d8..00000000 --- a/bin/mex +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# Make the first non-executable instance of files with the given names in $PATH -# executable -self=mex - -# Check we have at least one argument -if [ "$#" -eq 0 ] ; then - printf >&2 '%s: At least one name required\n' "$self" - exit 2 -fi - -# Iterate through the given names -for name ; do - - # Clear the found variable - found= - - # Start iterating through $PATH, with colon prefix/suffix to correctly - # handle the fenceposts - path=:$PATH: - while [ -n "$path" ] ; do - - # Pop the first directory off $path into $dir - dir=${path%%:*} - path=${path#*:} - - # Check $dir is non-null - [ -n "$dir" ] || continue - - # If a file with the needed name exists in the directory and isn't - # executable, we've found our candidate and can stop iterating - if [ -f "$dir"/"$name" ] && ! [ -x "$dir"/"$name" ] ; then - found=$dir/$name - break - fi - done - - # If the "found" variable was defined to something, we'll try to change its - # permissions - if [ -n "$found" ] ; then - chmod +x -- "$found" || ex=1 - - # If not, we'll report that we couldn't find it, and flag an error for the - # exit status - else - printf >&2 '%s: No non-executable name "%s" in PATH\n' "$self" "$name" - ex=1 - fi -done - -# We exit 1 if any of the names weren't found or if changing their permissions -# failed -exit "${ex:-0}" diff --git a/bin/mex.sh b/bin/mex.sh new file mode 100644 index 00000000..0b3d6c7e --- /dev/null +++ b/bin/mex.sh @@ -0,0 +1,52 @@ +# Make the first non-executable instance of files with the given names in $PATH +# executable +self=mex + +# Check we have at least one argument +if [ "$#" -eq 0 ] ; then + printf >&2 '%s: At least one name required\n' "$self" + exit 2 +fi + +# Iterate through the given names +for name ; do + + # Clear the found variable + found= + + # Start iterating through $PATH, with colon prefix/suffix to correctly + # handle the fenceposts + path=:$PATH: + while [ -n "$path" ] ; do + + # Pop the first directory off $path into $dir + dir=${path%%:*} + path=${path#*:} + + # Check $dir is non-null + [ -n "$dir" ] || continue + + # If a file with the needed name exists in the directory and isn't + # executable, we've found our candidate and can stop iterating + if [ -f "$dir"/"$name" ] && ! [ -x "$dir"/"$name" ] ; then + found=$dir/$name + break + fi + done + + # If the "found" variable was defined to something, we'll try to change its + # permissions + if [ -n "$found" ] ; then + chmod +x -- "$found" || ex=1 + + # If not, we'll report that we couldn't find it, and flag an error for the + # exit status + else + printf >&2 '%s: No non-executable name "%s" in PATH\n' "$self" "$name" + ex=1 + fi +done + +# We exit 1 if any of the names weren't found or if changing their permissions +# failed +exit "${ex:-0}" diff --git a/bin/mkcp b/bin/mkcp deleted file mode 100755 index 37bc87c0..00000000 --- a/bin/mkcp +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# Copy files into created directory in one call - -# 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/mkcp.sh b/bin/mkcp.sh new file mode 100644 index 00000000..10308263 --- /dev/null +++ b/bin/mkcp.sh @@ -0,0 +1,17 @@ +# Copy files into created directory in one call + +# 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 deleted file mode 100755 index 803ef05c..00000000 --- a/bin/mkmv +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# Move files into created directory in one call - -# 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/mkmv.sh b/bin/mkmv.sh new file mode 100644 index 00000000..53b5aa8f --- /dev/null +++ b/bin/mkmv.sh @@ -0,0 +1,17 @@ +# Move files into created directory in one call + +# 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 deleted file mode 100755 index 75bbb4b3..00000000 --- a/bin/mktd +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# Try to make a random temp directory - -# Get a random seed from rnds(1df); 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") - -# Create the directory and print its name if successful -mkdir -m 700 -- "$dn" && printf '%s\n' "$dn" diff --git a/bin/mktd.sh b/bin/mktd.sh new file mode 100644 index 00000000..62b10396 --- /dev/null +++ b/bin/mktd.sh @@ -0,0 +1,11 @@ +# Try to make a random temp directory + +# Get a random seed from rnds(1df); 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") + +# Create the directory and print its name if successful +mkdir -m 700 -- "$dn" && printf '%s\n' "$dn" diff --git a/bin/motd b/bin/motd deleted file mode 100755 index ee60ad03..00000000 --- a/bin/motd +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -# Show the system MOTD -motd=${MOTD:-/etc/motd} -[ -f "$motd" ] || exit -cat -- "$motd" diff --git a/bin/motd.sh b/bin/motd.sh new file mode 100644 index 00000000..4ac88081 --- /dev/null +++ b/bin/motd.sh @@ -0,0 +1,4 @@ +# Show the system MOTD +motd=${MOTD:-/etc/motd} +[ -f "$motd" ] || exit +cat -- "$motd" diff --git a/bin/murl b/bin/murl deleted file mode 100755 index 95db92c9..00000000 --- a/bin/murl +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# Format markdown and pass it to hurl to extract URLs from it. - -# Pipe the output of pandoc(1) on our args into hurl(1df) -pandoc -f markdown -t html -- "${@:-/dev/stdin}" | -hurl diff --git a/bin/murl.sh b/bin/murl.sh new file mode 100644 index 00000000..91304aa1 --- /dev/null +++ b/bin/murl.sh @@ -0,0 +1,5 @@ +# Format markdown and pass it to hurl to extract URLs from it. + +# Pipe the output of pandoc(1) on our args into hurl(1df) +pandoc -f markdown -t html -- "${@:-/dev/stdin}" | +hurl diff --git a/bin/osc b/bin/osc deleted file mode 100755 index 87f79365..00000000 --- a/bin/osc +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh -# Sane and safe OpenSSL s_client(1ssl) connection -self=osc - -# Check we have openssl(1); we need to fail early lest we go setting up FIFOs -# needlessly -if ! command -v openssl >/dev/null 2>&1 ; then - printf >&2 '%s: openssl(1) not found\n' "$self" - exit 1 -fi - -# Hostname is first argument; assume localhost if empty/unset -host=${1:-localhost} -# Service name or port is second argument; assume HTTPS if empty/unset -serv=${2:-https} - -# Start building the command-line string -set -- -## If we have rlwrap, use it, but don't complain if we don't -if command -v rlwrap >/dev/null 2>&1 ; then - set -- "$@" rlwrap -fi -## The actual openssl(1ssl) and subcommand call -set -- "$@" openssl s_client -## No insecure SSL methods -set -- "$@" -no_ssl2 -no_ssl3 -## Don't dump nonsense to terminal, and don't renegotiate on R or quit on Q -set -- "$@" -quiet -## But do cut the connection if I issue ^D, even though I just set -quiet -set -- "$@" -no_ign_eof -## Do verify the certificate chain and don't connect if we can't -set -- "$@" -verify 5 -verify_return_error -## We might add STARTTLS for the supported services: -case $serv in - ftp|21) - set -- "$@" -starttls ftp - ;; - smtp|25) - set -- "$@" -starttls smtp - ;; - pop3|110) - set -- "$@" -starttls pop3 - ;; - imap|143) - set -- "$@" -starttls imap - ;; - xmpp-client|5222) - set -- "$@" -starttls xmpp - ;; -esac -## Send the host parameter as the server name (SNI) -set -- "$@" -servername "$host" -## Finally, add the host and service to connect to -set -- "$@" -connect "$host":"$serv" - -# Do the POSIX dance to kill child processes and clean up temp files even if -# killed by a signal -td='' fil='' -cleanup() { - trap - EXIT "$1" - [ -n "$fil" ] && kill -TERM "$fil" - [ -n "$td" ] && rm -fr -- "$td" - if [ "$1" != EXIT ] ; then - kill -"$1" "$$" - fi -} -for sig in EXIT HUP INT TERM ; do - # shellcheck disable=SC2064 - trap "cleanup $sig" "$sig" -done - -# Create a temporary directory and a FIFO in it -td=$(mktd "$self") || exit -mkfifo -- "$td"/verify-filter || exit - -# Open a read-write file descriptor onto the FIFO -exec 3<>"$td"/verify-filter || exit - -# Start a background filter process on the FIFO to get rid of the leading -# verification output set to stderr; as soon as we find a single line that -# doesn't look like that routine output, print all future lines to stderr as -# normal -awk ' -body{print;next} -/^verify depth is [0-9]+$/{next} -/^depth=[0-9]+ /{next} -/^verify return:[0-9]+$/{next} -{body=1;print} -' <&3 >&2 & fil=$! - -# Start the process with the options we stacked up -"$@" 2>&3 diff --git a/bin/osc.sh b/bin/osc.sh new file mode 100644 index 00000000..ba35d9b7 --- /dev/null +++ b/bin/osc.sh @@ -0,0 +1,91 @@ +# Sane and safe OpenSSL s_client(1ssl) connection +self=osc + +# Check we have openssl(1); we need to fail early lest we go setting up FIFOs +# needlessly +if ! command -v openssl >/dev/null 2>&1 ; then + printf >&2 '%s: openssl(1) not found\n' "$self" + exit 1 +fi + +# Hostname is first argument; assume localhost if empty/unset +host=${1:-localhost} +# Service name or port is second argument; assume HTTPS if empty/unset +serv=${2:-https} + +# Start building the command-line string +set -- +## If we have rlwrap, use it, but don't complain if we don't +if command -v rlwrap >/dev/null 2>&1 ; then + set -- "$@" rlwrap +fi +## The actual openssl(1ssl) and subcommand call +set -- "$@" openssl s_client +## No insecure SSL methods +set -- "$@" -no_ssl2 -no_ssl3 +## Don't dump nonsense to terminal, and don't renegotiate on R or quit on Q +set -- "$@" -quiet +## But do cut the connection if I issue ^D, even though I just set -quiet +set -- "$@" -no_ign_eof +## Do verify the certificate chain and don't connect if we can't +set -- "$@" -verify 5 -verify_return_error +## We might add STARTTLS for the supported services: +case $serv in + ftp|21) + set -- "$@" -starttls ftp + ;; + smtp|25) + set -- "$@" -starttls smtp + ;; + pop3|110) + set -- "$@" -starttls pop3 + ;; + imap|143) + set -- "$@" -starttls imap + ;; + xmpp-client|5222) + set -- "$@" -starttls xmpp + ;; +esac +## Send the host parameter as the server name (SNI) +set -- "$@" -servername "$host" +## Finally, add the host and service to connect to +set -- "$@" -connect "$host":"$serv" + +# Do the POSIX dance to kill child processes and clean up temp files even if +# killed by a signal +td='' fil='' +cleanup() { + trap - EXIT "$1" + [ -n "$fil" ] && kill -TERM "$fil" + [ -n "$td" ] && rm -fr -- "$td" + if [ "$1" != EXIT ] ; then + kill -"$1" "$$" + fi +} +for sig in EXIT HUP INT TERM ; do + # shellcheck disable=SC2064 + trap "cleanup $sig" "$sig" +done + +# Create a temporary directory and a FIFO in it +td=$(mktd "$self") || exit +mkfifo -- "$td"/verify-filter || exit + +# Open a read-write file descriptor onto the FIFO +exec 3<>"$td"/verify-filter || exit + +# Start a background filter process on the FIFO to get rid of the leading +# verification output set to stderr; as soon as we find a single line that +# doesn't look like that routine output, print all future lines to stderr as +# normal +awk ' +body{print;next} +/^verify depth is [0-9]+$/{next} +/^depth=[0-9]+ /{next} +/^verify return:[0-9]+$/{next} +{body=1;print} +' <&3 >&2 & fil=$! + +# Start the process with the options we stacked up +"$@" 2>&3 diff --git a/bin/pa b/bin/pa deleted file mode 100755 index e03e1bb0..00000000 --- a/bin/pa +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Print arguments, one per line. Compare paz(1df). -[ "$#" -gt 0 ] || exit 0 -printf '%s\n' "$@" diff --git a/bin/pa.sh b/bin/pa.sh new file mode 100644 index 00000000..4cfa9dce --- /dev/null +++ b/bin/pa.sh @@ -0,0 +1,3 @@ +# Print arguments, one per line. Compare paz(1df). +[ "$#" -gt 0 ] || exit 0 +printf '%s\n' "$@" diff --git a/bin/paz b/bin/paz deleted file mode 100755 index b1f09ca9..00000000 --- a/bin/paz +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Print arguments, terminated by null chars. Compare pa(1df). -[ "$#" -gt 0 ] || exit 0 -printf '%s\0' "$@" diff --git a/bin/paz.sh b/bin/paz.sh new file mode 100644 index 00000000..e9b81bd7 --- /dev/null +++ b/bin/paz.sh @@ -0,0 +1,3 @@ +# Print arguments, terminated by null chars. Compare pa(1df). +[ "$#" -gt 0 ] || exit 0 +printf '%s\0' "$@" diff --git a/bin/pit b/bin/pit deleted file mode 100755 index d3068e76..00000000 --- a/bin/pit +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# If no arguments, we'll use stdin -if [ "$#" -eq 0 ] ; then - set -- - -fi - -# If output seems to be to a terminal, try to run input through a pager of some -# sort; we'll fall back on more(1) to be POSIX-ish -if [ -t 1 ] ; then - "${PAGER:-more}" -- "$@" - -# Otherwise, just run it through with cat(1); a good pager does this anyway, -# provided it actually exists -else - cat -- "$@" -fi diff --git a/bin/pit.sh b/bin/pit.sh new file mode 100644 index 00000000..377c1927 --- /dev/null +++ b/bin/pit.sh @@ -0,0 +1,16 @@ + +# If no arguments, we'll use stdin +if [ "$#" -eq 0 ] ; then + set -- - +fi + +# If output seems to be to a terminal, try to run input through a pager of some +# sort; we'll fall back on more(1) to be POSIX-ish +if [ -t 1 ] ; then + "${PAGER:-more}" -- "$@" + +# Otherwise, just run it through with cat(1); a good pager does this anyway, +# provided it actually exists +else + cat -- "$@" +fi diff --git a/bin/plmu b/bin/plmu deleted file mode 100755 index cf9b7eae..00000000 --- a/bin/plmu +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# Set up exceptions file if it exists -ef=$HOME/.plenv/non-cpanm-modules -[ -e "$ef" ] || ef=/dev/null - -# Check that exceptions file is sorted -if ! sort -c -- "$ef" ; then - printf >&2 '%s not sorted\n' "$ef" - exit 1 -fi - -# Get the list of modules; sort them in case our current locale disagrees on -# the existing sorting -plenv list-modules | sort | - -# Exclude any modules in ~.plenv/non-cpanm-modules if it exists -comm -23 -- - "$ef" | - -# Read that list of modules to upgrade and upgrade them one by one -while read -r module ; do - cpanm --notest --quiet -- "$module" -done diff --git a/bin/plmu.sh b/bin/plmu.sh new file mode 100644 index 00000000..d6f163e6 --- /dev/null +++ b/bin/plmu.sh @@ -0,0 +1,22 @@ + +# Set up exceptions file if it exists +ef=$HOME/.plenv/non-cpanm-modules +[ -e "$ef" ] || ef=/dev/null + +# Check that exceptions file is sorted +if ! sort -c -- "$ef" ; then + printf >&2 '%s not sorted\n' "$ef" + exit 1 +fi + +# Get the list of modules; sort them in case our current locale disagrees on +# the existing sorting +plenv list-modules | sort | + +# Exclude any modules in ~.plenv/non-cpanm-modules if it exists +comm -23 -- - "$ef" | + +# Read that list of modules to upgrade and upgrade them one by one +while read -r module ; do + cpanm --notest --quiet -- "$module" +done diff --git a/bin/pp b/bin/pp deleted file mode 100755 index d9fe6488..00000000 --- a/bin/pp +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Print the full path to each argument; path need not exist -for arg ; do - case $arg in - /*) path=$arg ;; - *) path=$PWD/$arg ;; - esac - printf '%s\n' "$path" -done diff --git a/bin/pp.sh b/bin/pp.sh new file mode 100644 index 00000000..b472a012 --- /dev/null +++ b/bin/pp.sh @@ -0,0 +1,8 @@ +# Print the full path to each argument; path need not exist +for arg ; do + case $arg in + /*) path=$arg ;; + *) path=$PWD/$arg ;; + esac + printf '%s\n' "$path" +done diff --git a/bin/pph b/bin/pph deleted file mode 100755 index 7987382f..00000000 --- a/bin/pph +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -# Run pp(1df) on args, prefix with machine hostname -hn=$(hostname -s) || exit -pp "$@" | -awk -v hn="$hn" '{ print hn ":" $0 }' diff --git a/bin/pph.sh b/bin/pph.sh new file mode 100644 index 00000000..268b6ad7 --- /dev/null +++ b/bin/pph.sh @@ -0,0 +1,4 @@ +# Run pp(1df) on args, prefix with machine hostname +hn=$(hostname -s) || exit +pp "$@" | +awk -v hn="$hn" '{ print hn ":" $0 }' diff --git a/bin/pwg b/bin/pwg deleted file mode 100755 index 97af3df4..00000000 --- a/bin/pwg +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -# Shortcut to generate just one strong password with pwgen(1) -# If any arguments are provided, those are used instead -if [ "$#" -eq 0 ] ; then - set -- --secure -- "${PWGEN_LENGTH:-16}" "${PWGEN_COUNT:-1}" -fi -pwgen "$@" diff --git a/bin/pwg.sh b/bin/pwg.sh new file mode 100644 index 00000000..e73ae97a --- /dev/null +++ b/bin/pwg.sh @@ -0,0 +1,6 @@ +# Shortcut to generate just one strong password with pwgen(1) +# If any arguments are provided, those are used instead +if [ "$#" -eq 0 ] ; then + set -- --secure -- "${PWGEN_LENGTH:-16}" "${PWGEN_COUNT:-1}" +fi +pwgen "$@" diff --git a/bin/rfcf b/bin/rfcf deleted file mode 100755 index 6f257415..00000000 --- a/bin/rfcf +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# Check arguments -if [ "$#" -ne 1 ] ; then - printf >&2 'rfcf: Need one RFC number\n' - exit 2 -fi - -# Argument is RFC number -rn=$1 - -# Retrieve the RFC with curl(1) -curl -fsSL https://tools.ietf.org/rfc/rfc"$rn".txt diff --git a/bin/rfcf.sh b/bin/rfcf.sh new file mode 100644 index 00000000..36b1a4c4 --- /dev/null +++ b/bin/rfcf.sh @@ -0,0 +1,12 @@ + +# Check arguments +if [ "$#" -ne 1 ] ; then + printf >&2 'rfcf: Need one RFC number\n' + exit 2 +fi + +# Argument is RFC number +rn=$1 + +# Retrieve the RFC with curl(1) +curl -fsSL https://tools.ietf.org/rfc/rfc"$rn".txt diff --git a/bin/rfcr b/bin/rfcr deleted file mode 100755 index 75d9abb0..00000000 --- a/bin/rfcr +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -# Check arguments -if [ "$#" -ne 1 ] ; then - printf >&2 'rfcf: Need one RFC number\n' - exit 2 -fi - -# Argument is RFC number -rn=$1 - -# Retrieve the RFC with rfcf(1df) -rfcf "$rn" | - -# Pipe it through rfct(1df) to format it as text -rfct | - -# Either spit it directly or through a pager -pit diff --git a/bin/rfcr.sh b/bin/rfcr.sh new file mode 100644 index 00000000..860ae53d --- /dev/null +++ b/bin/rfcr.sh @@ -0,0 +1,18 @@ + +# Check arguments +if [ "$#" -ne 1 ] ; then + printf >&2 'rfcf: Need one RFC number\n' + exit 2 +fi + +# Argument is RFC number +rn=$1 + +# Retrieve the RFC with rfcf(1df) +rfcf "$rn" | + +# Pipe it through rfct(1df) to format it as text +rfct | + +# Either spit it directly or through a pager +pit diff --git a/bin/rgl b/bin/rgl deleted file mode 100755 index a06ecd0a..00000000 --- a/bin/rgl +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# Read grep(1) patterns from input and search for them in the given files -self=rgl - -# Check the arguments -if [ "$#" -eq 0 ] ; then - printf >&2 '%s: Need at least one filename\n' "$self" - exit 2 -fi - -# Iterate over the patterns and search for each one -while { - - # If the input is a terminal, print a slash prompt for the next pattern; - # try to print it in bold red, too, but discard stderr if we can't - if [ -t 0 ] ; then - tput setaf 1 || tput setaf 1 0 0 || tput AF 1 || tput AF 1 0 0 - tput bold || tput md - printf '%s/' "$self" - tput sgr0 || tput me - fi 2>/dev/null - - # Read the pattern - IFS= read -r pat - -} ; do - - # Run grep(1) with the read pattern over the arguments - grep -- "$pat" "$@" -done - -# Print a newline if this was a terminal to clear the prompt -if [ -t 0 ] ; then - printf '\n' -fi diff --git a/bin/rgl.sh b/bin/rgl.sh new file mode 100644 index 00000000..630d38b6 --- /dev/null +++ b/bin/rgl.sh @@ -0,0 +1,34 @@ +# Read grep(1) patterns from input and search for them in the given files +self=rgl + +# Check the arguments +if [ "$#" -eq 0 ] ; then + printf >&2 '%s: Need at least one filename\n' "$self" + exit 2 +fi + +# Iterate over the patterns and search for each one +while { + + # If the input is a terminal, print a slash prompt for the next pattern; + # try to print it in bold red, too, but discard stderr if we can't + if [ -t 0 ] ; then + tput setaf 1 || tput setaf 1 0 0 || tput AF 1 || tput AF 1 0 0 + tput bold || tput md + printf '%s/' "$self" + tput sgr0 || tput me + fi 2>/dev/null + + # Read the pattern + IFS= read -r pat + +} ; do + + # Run grep(1) with the read pattern over the arguments + grep -- "$pat" "$@" +done + +# Print a newline if this was a terminal to clear the prompt +if [ -t 0 ] ; then + printf '\n' +fi diff --git a/bin/rnda b/bin/rnda deleted file mode 100755 index 5af4a3bd..00000000 --- a/bin/rnda +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# Choose a random argument using rndi(1df) - -# Check we have at least one argument -if [ "$#" -eq 0 ] ; then - printf >&2 'rnda: No args given\n' - exit 2 -fi - -# Get a random seed from rnds(1df); 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/rnda.sh b/bin/rnda.sh new file mode 100644 index 00000000..b09a8b6f --- /dev/null +++ b/bin/rnda.sh @@ -0,0 +1,19 @@ +# Choose a random argument using rndi(1df) + +# Check we have at least one argument +if [ "$#" -eq 0 ] ; then + printf >&2 'rnda: No args given\n' + exit 2 +fi + +# Get a random seed from rnds(1df); 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 deleted file mode 100755 index 67f9d997..00000000 --- a/bin/rndf +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# Choose a random file from a given directory using rnda(1df); 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/rndf.sh b/bin/rndf.sh new file mode 100644 index 00000000..21aa76a6 --- /dev/null +++ b/bin/rndf.sh @@ -0,0 +1,17 @@ +# Choose a random file from a given directory using rnda(1df); 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/rndl b/bin/rndl deleted file mode 100755 index c09c2c78..00000000 --- a/bin/rndl +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# 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' "$@" 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' "$@" diff --git a/bin/rnds b/bin/rnds deleted file mode 100755 index c5ffabe4..00000000 --- a/bin/rnds +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# Try to get a low-quality random seed from a random device if possible - -# 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 - -# 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/rnds.sh b/bin/rnds.sh new file mode 100644 index 00000000..6b3ac904 --- /dev/null +++ b/bin/rnds.sh @@ -0,0 +1,21 @@ +# Try to get a low-quality random seed from a random device if possible + +# 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 + +# 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/shb b/bin/shb deleted file mode 100755 index 72ac818b..00000000 --- a/bin/shb +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# Use PATH to build a shebang for a script given on stdin -self=shb - -# Need at least two arguments -if [ "$#" -lt 1 ] ; then - printf >&2 '%s: Need interpreter command\n' "$self" - exit 1 -fi - -# First argument is the name of the interpreter -intn=$1 -shift - -# Try and find the path to the interpreter command, bail out if we can't -if ! intp=$(command -v "$intn" 2>/dev/null) ; then - printf >&2 '%s: %s: command not found\n' "$self" "$intn" - exit 1 -fi - -# Set the positional parameters to the path and any remaining arguments, and -# squash them together for the shebang line -set -- "$intp" "$@" -printf '#!%s\n' "$*" - -# Emit the rest of the input -cat diff --git a/bin/shb.sh b/bin/shb.sh new file mode 100644 index 00000000..7d31876d --- /dev/null +++ b/bin/shb.sh @@ -0,0 +1,26 @@ +# Use PATH to build a shebang for a script given on stdin +self=shb + +# Need at least two arguments +if [ "$#" -lt 1 ] ; then + printf >&2 '%s: Need interpreter command\n' "$self" + exit 1 +fi + +# First argument is the name of the interpreter +intn=$1 +shift + +# Try and find the path to the interpreter command, bail out if we can't +if ! intp=$(command -v "$intn" 2>/dev/null) ; then + printf >&2 '%s: %s: command not found\n' "$self" "$intn" + exit 1 +fi + +# Set the positional parameters to the path and any remaining arguments, and +# squash them together for the shebang line +set -- "$intp" "$@" +printf '#!%s\n' "$*" + +# Emit the rest of the input +cat diff --git a/bin/slow b/bin/slow deleted file mode 100755 index a7bdae76..00000000 --- a/bin/slow +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Convert uppercase letters in a stream to lowercase -cat "${@:--}" | -tr '[:upper:]' '[:lower:]' diff --git a/bin/slow.sh b/bin/slow.sh new file mode 100644 index 00000000..b0047829 --- /dev/null +++ b/bin/slow.sh @@ -0,0 +1,3 @@ +# Convert uppercase letters in a stream to lowercase +cat "${@:--}" | +tr '[:upper:]' '[:lower:]' diff --git a/bin/sls b/bin/sls deleted file mode 100755 index 770b8ec0..00000000 --- a/bin/sls +++ /dev/null @@ -1,20 +0,0 @@ -#!/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(1df) over the ones we did collect -slsf -- "$@" diff --git a/bin/sls.sh b/bin/sls.sh new file mode 100644 index 00000000..55c1dfc7 --- /dev/null +++ b/bin/sls.sh @@ -0,0 +1,19 @@ +# 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(1df) over the ones we did collect +slsf -- "$@" diff --git a/bin/sqs b/bin/sqs deleted file mode 100755 index d0b3023f..00000000 --- a/bin/sqs +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# Chop a trailing query string off filenames -self=sqs - -# Check args -if [ "$#" -eq 0 ] ; then - printf >&2 '%s: Need a filename\n' "$self" - exit 2 -fi - -# Iterate through the given files -for sn ; do - - # Strip trailing slash if any and then query string - sn=${sn%/} - dn=${sn%%\?*} - - # Ignore this file if its name wouldn't change - [ "$sn" != "$dn" ] || continue - - # Ignore this file if its name already exists (don't overwrite) - if [ -e "$dn" ] ; then - printf >&2 '%s: File named %s already exists\n' \ - "$self" "$dn" - ex=1 - continue - fi - - # Attempt a rename, flag an error if there was one - mv -- "$sn" "$dn" || ex=1 -done - -# Exit with 1 if there was any failed mv(1) run -exit "${ex:-0}" diff --git a/bin/sqs.sh b/bin/sqs.sh new file mode 100644 index 00000000..e00797e3 --- /dev/null +++ b/bin/sqs.sh @@ -0,0 +1,33 @@ +# Chop a trailing query string off filenames +self=sqs + +# Check args +if [ "$#" -eq 0 ] ; then + printf >&2 '%s: Need a filename\n' "$self" + exit 2 +fi + +# Iterate through the given files +for sn ; do + + # Strip trailing slash if any and then query string + sn=${sn%/} + dn=${sn%%\?*} + + # Ignore this file if its name wouldn't change + [ "$sn" != "$dn" ] || continue + + # Ignore this file if its name already exists (don't overwrite) + if [ -e "$dn" ] ; then + printf >&2 '%s: File named %s already exists\n' \ + "$self" "$dn" + ex=1 + continue + fi + + # Attempt a rename, flag an error if there was one + mv -- "$sn" "$dn" || ex=1 +done + +# Exit with 1 if there was any failed mv(1) run +exit "${ex:-0}" diff --git a/bin/sra b/bin/sra deleted file mode 100755 index 7f072dfb..00000000 --- a/bin/sra +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# Run ssh(1) with an optional command on every host in sls(1df) output -# Use FD3 to keep a reference to the script's stdin for the ssh(1) calls -exec 3<&0 -sls | while read -r hostname ; do - printf 'sra: %s\n' "$hostname" - ssh -qt -- "$hostname" "$@" <&3 # shellcheck disable=SC2029 -done diff --git a/bin/sra.sh b/bin/sra.sh new file mode 100644 index 00000000..f3ed6f71 --- /dev/null +++ b/bin/sra.sh @@ -0,0 +1,7 @@ +# Run ssh(1) with an optional command on every host in sls(1df) output +# Use FD3 to keep a reference to the script's stdin for the ssh(1) calls +exec 3<&0 +sls | while read -r hostname ; do + printf 'sra: %s\n' "$hostname" + ssh -qt -- "$hostname" "$@" <&3 # shellcheck disable=SC2029 +done diff --git a/bin/sshi b/bin/sshi deleted file mode 100755 index 80e00a10..00000000 --- a/bin/sshi +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# Print some human-readable information from SSH_CONNECTION - -# Check we have an SSH_CONNECTION variable -if [ -z "$SSH_CONNECTION" ] ; then - printf >&2 'sshi: SSH_CONNECTION appears empty\n' - exit 1 -fi - -# Print the two variables into a compound command so we can `read` them -printf '%s\n' "$SSH_CONNECTION" "${SSH_TTY:-unknown}" | -{ - # Read connection details from first line - read -r ci cp si sp - - # Read TTY from second line - read -r tty - - # Try to resolve the client and server IPs - ch=$(dig -x "$ci" +short 2>/dev/null | sed 's/\.$//;1q') - sh=$(dig -x "$si" +short 2>/dev/null | sed 's/\.$//;1q') - - # Print the results in a human-readable format - printf "%s:%u -> %s:%u (%s)\n" \ - "${ch:-"$ci"}" "$cp" \ - "${sh:-"$si"}" "$sp" \ - "$tty" -} diff --git a/bin/sshi.sh b/bin/sshi.sh new file mode 100644 index 00000000..0d1591f1 --- /dev/null +++ b/bin/sshi.sh @@ -0,0 +1,27 @@ +# Print some human-readable information from SSH_CONNECTION + +# Check we have an SSH_CONNECTION variable +if [ -z "$SSH_CONNECTION" ] ; then + printf >&2 'sshi: SSH_CONNECTION appears empty\n' + exit 1 +fi + +# Print the two variables into a compound command so we can `read` them +printf '%s\n' "$SSH_CONNECTION" "${SSH_TTY:-unknown}" | +{ + # Read connection details from first line + read -r ci cp si sp + + # Read TTY from second line + read -r tty + + # Try to resolve the client and server IPs + ch=$(dig -x "$ci" +short 2>/dev/null | sed 's/\.$//;1q') + sh=$(dig -x "$si" +short 2>/dev/null | sed 's/\.$//;1q') + + # Print the results in a human-readable format + printf "%s:%u -> %s:%u (%s)\n" \ + "${ch:-"$ci"}" "$cp" \ + "${sh:-"$si"}" "$sp" \ + "$tty" +} diff --git a/bin/sta b/bin/sta deleted file mode 100755 index 848d9740..00000000 --- a/bin/sta +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# Print list of sls(1df) hostnames that exit 0 when a connection is attempted -# and the optional given command is run. Discard stdout, but preserve stderr. -sls | while read -r hostname ; do - # shellcheck disable=SC2029 - ssh -nq -- "$hostname" "$@" >/dev/null || continue - printf '%s\n' "$hostname" -done diff --git a/bin/sta.sh b/bin/sta.sh new file mode 100644 index 00000000..5736842a --- /dev/null +++ b/bin/sta.sh @@ -0,0 +1,7 @@ +# Print list of sls(1df) hostnames that exit 0 when a connection is attempted +# and the optional given command is run. Discard stdout, but preserve stderr. +sls | while read -r hostname ; do + # shellcheck disable=SC2029 + ssh -nq -- "$hostname" "$@" >/dev/null || continue + printf '%s\n' "$hostname" +done diff --git a/bin/stbl b/bin/stbl deleted file mode 100755 index 34a06251..00000000 --- a/bin/stbl +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# Strip a trailing blank line from the given files with ed(1) - -# Check arguments -if [ "$#" -eq 0 ] ; then - printf >&2 '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' || 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/stbl.sh b/bin/stbl.sh new file mode 100644 index 00000000..23d77703 --- /dev/null +++ b/bin/stbl.sh @@ -0,0 +1,18 @@ +# Strip a trailing blank line from the given files with ed(1) + +# Check arguments +if [ "$#" -eq 0 ] ; then + printf >&2 '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' || 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 deleted file mode 100755 index f1f9c029..00000000 --- a/bin/stex +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# Strip an extension from the given filenames -self=stex - -# Check args -if [ "$#" -lt 2 ] ; then - printf >&2 '%s: Need an extension .ext and a filename\n' \ - "$self" - exit 2 -fi - -# 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 - - # Ignore this file if its name already exists (don't overwrite) - if [ -e "$dn" ] ; then - printf >&2 '%s: File named %s already exists\n' \ - "$self" "$dn" - ex=1 - continue - fi - - # Attempt a rename, flag an error if there was one - mv -- "$sn" "$dn" || ex=1 -done - -# Exit with 1 if there was any failed mv(1) run -exit "${ex:-0}" diff --git a/bin/stex.sh b/bin/stex.sh new file mode 100644 index 00000000..14d2cabf --- /dev/null +++ b/bin/stex.sh @@ -0,0 +1,38 @@ +# Strip an extension from the given filenames +self=stex + +# Check args +if [ "$#" -lt 2 ] ; then + printf >&2 '%s: Need an extension .ext and a filename\n' \ + "$self" + exit 2 +fi + +# 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 + + # Ignore this file if its name already exists (don't overwrite) + if [ -e "$dn" ] ; then + printf >&2 '%s: File named %s already exists\n' \ + "$self" "$dn" + ex=1 + continue + fi + + # Attempt a rename, flag an error if there was one + mv -- "$sn" "$dn" || ex=1 +done + +# Exit with 1 if there was any failed mv(1) run +exit "${ex:-0}" diff --git a/bin/stws b/bin/stws deleted file mode 100755 index 2ceae935..00000000 --- a/bin/stws +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# Strip trailing spaces on one or more files - -# Check arguments -if [ "$#" -eq 0 ] ; then - printf >&2 'stws: 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' || 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/stws.sh b/bin/stws.sh new file mode 100644 index 00000000..ce2c14d0 --- /dev/null +++ b/bin/stws.sh @@ -0,0 +1,18 @@ +# Strip trailing spaces on one or more files + +# Check arguments +if [ "$#" -eq 0 ] ; then + printf >&2 'stws: 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' || 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 deleted file mode 100755 index 64d566f7..00000000 --- a/bin/sue +++ /dev/null @@ -1,27 +0,0 @@ -#!/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 - ;; - *) - printf >&2 'sue: Files do not share a common owner\n' - exit 1 - ;; - esac -done - -# Run sudoedit(8) as the user that owns all the files -sudoedit -u "$user" -- "$@" diff --git a/bin/sue.sh b/bin/sue.sh new file mode 100644 index 00000000..654c041f --- /dev/null +++ b/bin/sue.sh @@ -0,0 +1,26 @@ +# 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 + ;; + *) + printf >&2 'sue: Files do not share a common owner\n' + exit 1 + ;; + esac +done + +# Run sudoedit(8) as the user that owns all the files +sudoedit -u "$user" -- "$@" diff --git a/bin/supp b/bin/supp deleted file mode 100755 index 1ba6c850..00000000 --- a/bin/supp +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Convert lowercase letters in a stream to uppercase -cat "${@:--}" | -tr '[:lower:]' '[:upper:]' diff --git a/bin/supp.sh b/bin/supp.sh new file mode 100644 index 00000000..5ddbadc3 --- /dev/null +++ b/bin/supp.sh @@ -0,0 +1,3 @@ +# Convert lowercase letters in a stream to uppercase +cat "${@:--}" | +tr '[:lower:]' '[:upper:]' diff --git a/bin/swr b/bin/swr deleted file mode 100755 index 56ab5919..00000000 --- a/bin/swr +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/sh -# Transparently wrap scp(1) targets on the command line -self=swr - -# 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 - -# Set a flag to manage resetting the positional parameters at the start of the -# loop -n=1 -for arg ; do - - # If this is our first iteration, reset the shell parameters - case $n in - 1) set -- ;; - esac - - # Test whether this argument looks like a remote file - if ( - - # Test it contains a colon - case $arg in - *:*) ;; - *) exit 1 ;; - esac - - # Test the part before the first colon has at least one character and - # only hostname characters - case ${arg%%:*} in - '') exit 1 ;; - *[!a-zA-Z0-9-.]*) exit 1 ;; - esac - - ) ; then - - # Looks like a remote file request; try to copy it into the temporary - # directory, bail out completely if we can't - dst=$td/$n - scp -q -- "$arg" "$dst" || exit - set -- "$@" "$dst" - - else - # Just a plain old argument; stack it up - set -- "$@" "$arg" - fi - - # Bump n - n=$((n+1)) -done - -# Run the command with the processed arguments -exec "$@" diff --git a/bin/swr.sh b/bin/swr.sh new file mode 100644 index 00000000..47c84b86 --- /dev/null +++ b/bin/swr.sh @@ -0,0 +1,64 @@ +# Transparently wrap scp(1) targets on the command line +self=swr + +# 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 + +# Set a flag to manage resetting the positional parameters at the start of the +# loop +n=1 +for arg ; do + + # If this is our first iteration, reset the shell parameters + case $n in + 1) set -- ;; + esac + + # Test whether this argument looks like a remote file + if ( + + # Test it contains a colon + case $arg in + *:*) ;; + *) exit 1 ;; + esac + + # Test the part before the first colon has at least one character and + # only hostname characters + case ${arg%%:*} in + '') exit 1 ;; + *[!a-zA-Z0-9-.]*) exit 1 ;; + esac + + ) ; then + + # Looks like a remote file request; try to copy it into the temporary + # directory, bail out completely if we can't + dst=$td/$n + scp -q -- "$arg" "$dst" || exit + set -- "$@" "$dst" + + else + # Just a plain old argument; stack it up + set -- "$@" "$arg" + fi + + # Bump n + n=$((n+1)) +done + +# Run the command with the processed arguments +exec "$@" diff --git a/bin/td b/bin/td deleted file mode 100755 index 69077a8d..00000000 --- a/bin/td +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# Manage to-do files with just $EDITOR and git(1) - -# Specify the path and file -dir=${TODO_DIR:-"$HOME"/Todo} -file=${1:-"${TODO_NAME:-todo}"} - -# If the directory doesn't exist, create it -[ -d "$dir" ] || mkdir -p -- "$dir" || exit - -# Change into the directory -cd -- "$dir" || exit - -# If the current directory isn't a Git repository, try to create one -if ! command -v isgr >/dev/null 2>&1 ; then - printf >&2 'isgr: command not found\n' - exit 1 -fi -isgr || git init || exit - -# If the to-do file doesn't exist yet, create it -[ -e "$file" ] || touch -- "$file" || exit - -# Launch an appropriate editor to edit that file -"${VISUAL:-"${EDITOR:-ed}"}" "$file" - -# Add the file to the changeset -git add -- "$file" - -# If there are changes to commit, commit them -git diff-index --quiet HEAD || -git commit --message 'Changed by td(1df)' --quiet diff --git a/bin/td.sh b/bin/td.sh new file mode 100644 index 00000000..eaae1fd6 --- /dev/null +++ b/bin/td.sh @@ -0,0 +1,31 @@ +# Manage to-do files with just $EDITOR and git(1) + +# Specify the path and file +dir=${TODO_DIR:-"$HOME"/Todo} +file=${1:-"${TODO_NAME:-todo}"} + +# If the directory doesn't exist, create it +[ -d "$dir" ] || mkdir -p -- "$dir" || exit + +# Change into the directory +cd -- "$dir" || exit + +# If the current directory isn't a Git repository, try to create one +if ! command -v isgr >/dev/null 2>&1 ; then + printf >&2 'isgr: command not found\n' + exit 1 +fi +isgr || git init || exit + +# If the to-do file doesn't exist yet, create it +[ -e "$file" ] || touch -- "$file" || exit + +# Launch an appropriate editor to edit that file +"${VISUAL:-"${EDITOR:-ed}"}" "$file" + +# Add the file to the changeset +git add -- "$file" + +# If there are changes to commit, commit them +git diff-index --quiet HEAD || +git commit --message 'Changed by td(1df)' --quiet diff --git a/bin/tl b/bin/tl deleted file mode 100755 index baa6fb2b..00000000 --- a/bin/tl +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# Tag lines from files or stdin with a string prefix or suffix -self=tl - -# Parse options out -while getopts 'p:s:' opt ; do - case $opt in - - # Prefix - p) pref=$OPTARG ;; - - # Suffix - s) suff=$OPTARG ;; - - # Unknown option - \?) - printf >&2 '%s: Unknown option %s\n' \ - "$self" "$opt" - exit 2 - ;; - esac -done -shift "$((OPTIND-1))" - -# Print each line as we read it, adding the tags -cat -- "${@:--}" | -while IFS= read -r line ; do - printf '%s%s%s\n' "$pref" "$line" "$suff" -done diff --git a/bin/tl.sh b/bin/tl.sh new file mode 100644 index 00000000..86bca469 --- /dev/null +++ b/bin/tl.sh @@ -0,0 +1,28 @@ +# Tag lines from files or stdin with a string prefix or suffix +self=tl + +# Parse options out +while getopts 'p:s:' opt ; do + case $opt in + + # Prefix + p) pref=$OPTARG ;; + + # Suffix + s) suff=$OPTARG ;; + + # Unknown option + \?) + printf >&2 '%s: Unknown option %s\n' \ + "$self" "$opt" + exit 2 + ;; + esac +done +shift "$((OPTIND-1))" + +# Print each line as we read it, adding the tags +cat -- "${@:--}" | +while IFS= read -r line ; do + printf '%s%s%s\n' "$pref" "$line" "$suff" +done diff --git a/bin/tlcs b/bin/tlcs deleted file mode 100755 index aa0d2f25..00000000 --- a/bin/tlcs +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/sh -# Execute a command and tag the output of the stdout and stderr streams. -self=tlcs - -# Set the default prefixes and suffixes for stdout/err -out_pref='stdout: ' -err_pref='stderr: ' -out_suff= -err_suff= - -# Parse options out, give help if necessary -while getopts 'co:e:' opt ; do - case $opt in - c) - color=1 - ;; - o) - out_pref=$OPTARG - ;; - e) - err_pref=$OPTARG - ;; - \?) - printf >&2 'Unknown option %s\n' "$opt" - exit 2 - ;; - esac -done -shift "$((OPTIND-1))" - -# We need at least one more argument -if [ "$#" -eq 0 ] ; then - printf >&2 '%s: Need a command to run\n' "$self" - exit 2 -fi - -# If color was requested for the output, try and get a count of available -# colors; otherwise default to zero -[ -n "$color" ] && color_count=$( { - tput colors || tput Co -} 2>/dev/null ) -: "${color_count:=0}" - -# If the color count is 8 or greater, we'll color the output -if [ "$((color_count >= 8))" -eq 1 ] ; then - - # Color code for resetting - color_reset=$( { - tput me || tput sgr0 - } 2>/dev/null ) - - # If stdout is a terminal, color it - if [ -t 1 ] ; then - color_stdout=$( { - tput AF 2 || tput setaf 2 - } 2>/dev/null ) - out_pref=${color_stdout}${out_pref} - out_suff=${out_suff}${color_reset} - fi - - # If stderr is a terminal, color it - if [ -t 2 ] ; then - color_stderr=$( { - tput AF 1 || tput setaf 1 - } 2>/dev/null ) - err_pref=${color_stderr}${err_pref} - out_suff=${err_suff}${color_reset} - fi -fi - -# 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 - -# Execute the command, passing stdout and stderr to tl(1df) calls as appropriate -# via named pipes -out=$td/out err=$td/err -mkfifo -- "$out" "$err" || exit -tl -p "$out_pref" -s "$out_suff" < "$out" & -tl -p "$err_pref" -s "$err_suff" < "$err" & -"$@" >"$out" 2>"$err" -ex=$? ; wait ; exit "$ex" diff --git a/bin/tlcs.sh b/bin/tlcs.sh new file mode 100644 index 00000000..f20b160e --- /dev/null +++ b/bin/tlcs.sh @@ -0,0 +1,93 @@ +# Execute a command and tag the output of the stdout and stderr streams. +self=tlcs + +# Set the default prefixes and suffixes for stdout/err +out_pref='stdout: ' +err_pref='stderr: ' +out_suff= +err_suff= + +# Parse options out, give help if necessary +while getopts 'co:e:' opt ; do + case $opt in + c) + color=1 + ;; + o) + out_pref=$OPTARG + ;; + e) + err_pref=$OPTARG + ;; + \?) + printf >&2 'Unknown option %s\n' "$opt" + exit 2 + ;; + esac +done +shift "$((OPTIND-1))" + +# We need at least one more argument +if [ "$#" -eq 0 ] ; then + printf >&2 '%s: Need a command to run\n' "$self" + exit 2 +fi + +# If color was requested for the output, try and get a count of available +# colors; otherwise default to zero +[ -n "$color" ] && color_count=$( { + tput colors || tput Co +} 2>/dev/null ) +: "${color_count:=0}" + +# If the color count is 8 or greater, we'll color the output +if [ "$((color_count >= 8))" -eq 1 ] ; then + + # Color code for resetting + color_reset=$( { + tput me || tput sgr0 + } 2>/dev/null ) + + # If stdout is a terminal, color it + if [ -t 1 ] ; then + color_stdout=$( { + tput AF 2 || tput setaf 2 + } 2>/dev/null ) + out_pref=${color_stdout}${out_pref} + out_suff=${out_suff}${color_reset} + fi + + # If stderr is a terminal, color it + if [ -t 2 ] ; then + color_stderr=$( { + tput AF 1 || tput setaf 1 + } 2>/dev/null ) + err_pref=${color_stderr}${err_pref} + out_suff=${err_suff}${color_reset} + fi +fi + +# 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 + +# Execute the command, passing stdout and stderr to tl(1df) calls as appropriate +# via named pipes +out=$td/out err=$td/err +mkfifo -- "$out" "$err" || exit +tl -p "$out_pref" -s "$out_suff" < "$out" & +tl -p "$err_pref" -s "$err_suff" < "$err" & +"$@" >"$out" 2>"$err" +ex=$? ; wait ; exit "$ex" diff --git a/bin/tm b/bin/tm deleted file mode 100755 index f2b51c63..00000000 --- a/bin/tm +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# Attach to existing tmux session rather than create a new one if possible - -# If given any arguments, just use them as they are -if [ "$#" -gt 0 ] ; then - : - -# If a session exists, just attach to it -elif command tmux has-session 2>/dev/null ; then - set -- attach-session -d - -# Create a new session with an appropriate name -else - set -- new-session -s "${TMUX_SESSION:-default}" -fi - -# Execute with concluded arguments -tmux "$@" diff --git a/bin/tm.sh b/bin/tm.sh new file mode 100644 index 00000000..774dccb1 --- /dev/null +++ b/bin/tm.sh @@ -0,0 +1,17 @@ +# Attach to existing tmux session rather than create a new one if possible + +# If given any arguments, just use them as they are +if [ "$#" -gt 0 ] ; then + : + +# If a session exists, just attach to it +elif command tmux has-session 2>/dev/null ; then + set -- attach-session -d + +# Create a new session with an appropriate name +else + set -- new-session -s "${TMUX_SESSION:-default}" +fi + +# Execute with concluded arguments +tmux "$@" diff --git a/bin/try b/bin/try deleted file mode 100755 index 7d6d57a8..00000000 --- a/bin/try +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh -# Attempt a certain number of times to perform a task, buffer stderr unless and -# until all command attempts fail -self=try - -# Parse options -while getopts 's:n:' opt ; do - case $opt in - n) - attn=$OPTARG - ;; - s) - sleep=$OPTARG - ;; - \?) - printf >&2 '%s: Unknown option\n' "$self" - exit 2 - ;; - esac -done -shift "$((OPTIND-1))" - -# Check we have at least one argument left (the command to run) -if [ "$#" -eq 0 ] ; then - printf >&2 '%s: Need a command to run\n' "$self" - exit 2 -fi - -# 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 - -# Open a filehandle to the error buffer, just to save on file operations -errbuff=$td/errbuff -exec 3>"$errbuff" - -# Keep trying the command, writing error output to the buffer file, and exit -# if we succeed on any of them -attc=1 -: "${attn:=3}" "${sleep:=0}" -while [ "$attc" -le "$attn" ] ; do - - # Try running the command; if it succeeds, we're done, and any previous - # failures get their errors discarded - if "$@" 2>&3 ; then - exit - - # If the command failed, record the exit value - else - ex=$? - fi - - # If this isn't the last run, have a sleep - if [ "$attc" -lt "$attn" ] ; then - sleep "${sleep:=0}" - fi - - # Increment the attempt count - attc=$((attc + 1)) -done - -# Attempts were exhausted, and all failed; print the error output from all of -# the failures and exit with the non-zero exit value of the most recent one -exec 3>&- -cat -- "$td"/errbuff >&2 -exit "$ex" diff --git a/bin/try.sh b/bin/try.sh new file mode 100644 index 00000000..20ccbe5f --- /dev/null +++ b/bin/try.sh @@ -0,0 +1,77 @@ +# Attempt a certain number of times to perform a task, buffer stderr unless and +# until all command attempts fail +self=try + +# Parse options +while getopts 's:n:' opt ; do + case $opt in + n) + attn=$OPTARG + ;; + s) + sleep=$OPTARG + ;; + \?) + printf >&2 '%s: Unknown option\n' "$self" + exit 2 + ;; + esac +done +shift "$((OPTIND-1))" + +# Check we have at least one argument left (the command to run) +if [ "$#" -eq 0 ] ; then + printf >&2 '%s: Need a command to run\n' "$self" + exit 2 +fi + +# 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 + +# Open a filehandle to the error buffer, just to save on file operations +errbuff=$td/errbuff +exec 3>"$errbuff" + +# Keep trying the command, writing error output to the buffer file, and exit +# if we succeed on any of them +attc=1 +: "${attn:=3}" "${sleep:=0}" +while [ "$attc" -le "$attn" ] ; do + + # Try running the command; if it succeeds, we're done, and any previous + # failures get their errors discarded + if "$@" 2>&3 ; then + exit + + # If the command failed, record the exit value + else + ex=$? + fi + + # If this isn't the last run, have a sleep + if [ "$attc" -lt "$attn" ] ; then + sleep "${sleep:=0}" + fi + + # Increment the attempt count + attc=$((attc + 1)) +done + +# Attempts were exhausted, and all failed; print the error output from all of +# the failures and exit with the non-zero exit value of the most recent one +exec 3>&- +cat -- "$td"/errbuff >&2 +exit "$ex" diff --git a/bin/u2d b/bin/u2d deleted file mode 100755 index 505b3d04..00000000 --- a/bin/u2d +++ /dev/null @@ -1,27 +0,0 @@ -#!/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" <&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" <&2 'umake: No makefile found in ancestors\n' -exit 1 diff --git a/bin/umake.sh b/bin/umake.sh new file mode 100644 index 00000000..21073328 --- /dev/null +++ b/bin/umake.sh @@ -0,0 +1,10 @@ +# Keep going up the tree until we find a Makefile, and then run make(1) with +# any given args +while [ "$PWD" != / ] ; do + for mf in makefile Makefile ; do + [ -f "$mf" ] && exec make "$@" + done + cd .. || exit +done +printf >&2 'umake: No makefile found in ancestors\n' +exit 1 diff --git a/bin/urlc b/bin/urlc deleted file mode 100755 index a949f50d..00000000 --- a/bin/urlc +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh -# Try to find erroneous or insecure URLs -self=urlc - -# cURL request timeout -tm=${URLCHECK_TIMEOUT:-8} - -# 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 - -# Create buffer files for the headers and body content, to be cleaned up on -# exit -list=$td/list head=$td/head body=$td/body - -# Iterate through input; ignore leading/trailing whitespace -cat -- "${@:--}" >"$list" -while read -r url ; do - - # Skip anything that doesn't start with HTTP - case $url in - http*) ;; - *) continue ;; - esac - - # Make initial request, log head and body to files, cry and skip on error - if ! curl -A Mozilla -fHLsS -D "$head" -m "$tm" -o "$body" -- \ - "$url" ; then - printf >&2 '%s: %s raises error\n' \ - "$self" "$url" - ex=1 - continue - fi - - # Iterate through header file, cry about the first redirect we find - while IFS=': ' read -r header value ; do - [ "$header" = 'Location' ] || continue - printf >&2 '%s: %s redirects to %s\n' \ - "$self" "$url" "$value" >&2 - ex=1 - break - done < "$head" - - # Skip anything that's already secure - case $url in - https*) continue ;; - *) ;; - esac - - # Form a naïve attempt at a possible secure URL and try to request it, - # point it out if it actually works - surl=https://${url#http://} - if curl -A Mozilla -fLsS -D "$head" -m "$tm" -o "$body" -- \ - "$surl" 2>/dev/null ; then - printf >&2 '%s: %s has a working secure version at %s\n' \ - "$self" "$url" "$surl" - ex=1 - fi -done <"$list" - -# Wait for the input process to finish -wait - -# Exit if any errors -exit "${ex:-0}" diff --git a/bin/urlc.sh b/bin/urlc.sh new file mode 100644 index 00000000..0e6530fa --- /dev/null +++ b/bin/urlc.sh @@ -0,0 +1,76 @@ +# Try to find erroneous or insecure URLs +self=urlc + +# cURL request timeout +tm=${URLCHECK_TIMEOUT:-8} + +# 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 + +# Create buffer files for the headers and body content, to be cleaned up on +# exit +list=$td/list head=$td/head body=$td/body + +# Iterate through input; ignore leading/trailing whitespace +cat -- "${@:--}" >"$list" +while read -r url ; do + + # Skip anything that doesn't start with HTTP + case $url in + http*) ;; + *) continue ;; + esac + + # Make initial request, log head and body to files, cry and skip on error + if ! curl -A Mozilla -fHLsS -D "$head" -m "$tm" -o "$body" -- \ + "$url" ; then + printf >&2 '%s: %s raises error\n' \ + "$self" "$url" + ex=1 + continue + fi + + # Iterate through header file, cry about the first redirect we find + while IFS=': ' read -r header value ; do + [ "$header" = 'Location' ] || continue + printf >&2 '%s: %s redirects to %s\n' \ + "$self" "$url" "$value" >&2 + ex=1 + break + done < "$head" + + # Skip anything that's already secure + case $url in + https*) continue ;; + *) ;; + esac + + # Form a naïve attempt at a possible secure URL and try to request it, + # point it out if it actually works + surl=https://${url#http://} + if curl -A Mozilla -fLsS -D "$head" -m "$tm" -o "$body" -- \ + "$surl" 2>/dev/null ; then + printf >&2 '%s: %s has a working secure version at %s\n' \ + "$self" "$url" "$surl" + ex=1 + fi +done <"$list" + +# Wait for the input process to finish +wait + +# Exit if any errors +exit "${ex:-0}" diff --git a/bin/urlh b/bin/urlh deleted file mode 100755 index 8e9463e7..00000000 --- a/bin/urlh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# Get values for HTTP headers for the given URL - -# Check arguments -if [ "$#" -ne 2 ] ; then - printf 'urlt: Need an URL and a header name\n' - exit 2 -fi -url=$1 header=$2 - -# Run cURL header request -curl -fIsSL -- "$url" | - -# Unfold the headers -unf | - -# Change the line endings to UNIX format -sd2u | - -# Use awk to find any values for the header case-insensitively -awk -v header="$header" ' -BEGIN { - FS=": *" - header = tolower(header) -} -tolower($1) == header { - sub(/^[^ ]*: */, "") - print -} -' diff --git a/bin/urlh.sh b/bin/urlh.sh new file mode 100644 index 00000000..5b5cab74 --- /dev/null +++ b/bin/urlh.sh @@ -0,0 +1,29 @@ +# Get values for HTTP headers for the given URL + +# Check arguments +if [ "$#" -ne 2 ] ; then + printf 'urlt: Need an URL and a header name\n' + exit 2 +fi +url=$1 header=$2 + +# Run cURL header request +curl -fIsSL -- "$url" | + +# Unfold the headers +unf | + +# Change the line endings to UNIX format +sd2u | + +# Use awk to find any values for the header case-insensitively +awk -v header="$header" ' +BEGIN { + FS=": *" + header = tolower(header) +} +tolower($1) == header { + sub(/^[^ ]*: */, "") + print +} +' diff --git a/bin/urlmt b/bin/urlmt deleted file mode 100755 index b209f26a..00000000 --- a/bin/urlmt +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Get the MIME type for a given URL -urlh "$1" Content-Type | - -# Use last line only, remove any charset suffix -sed ' -$!d -s/;.*// -' diff --git a/bin/urlmt.sh b/bin/urlmt.sh new file mode 100644 index 00000000..cd71b0fd --- /dev/null +++ b/bin/urlmt.sh @@ -0,0 +1,8 @@ +# Get the MIME type for a given URL +urlh "$1" Content-Type | + +# Use last line only, remove any charset suffix +sed ' +$!d +s/;.*// +' diff --git a/bin/vest b/bin/vest deleted file mode 100755 index f857d8c1..00000000 --- a/bin/vest +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -# Run a test(1) command and print a string to stdout showing pass/fail -if [ "$#" -eq 0 ] ; then - printf >&2 'vest: Need test(1) arguments\n' - exit 2 -fi -vex test "$@" diff --git a/bin/vest.sh b/bin/vest.sh new file mode 100644 index 00000000..7dd65f0b --- /dev/null +++ b/bin/vest.sh @@ -0,0 +1,6 @@ +# Run a test(1) command and print a string to stdout showing pass/fail +if [ "$#" -eq 0 ] ; then + printf >&2 'vest: Need test(1) arguments\n' + exit 2 +fi +vex test "$@" diff --git a/bin/vex b/bin/vex deleted file mode 100755 index 908288ba..00000000 --- a/bin/vex +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# Run a command and print a string to stdout showing pass/fail -if [ "$#" -eq 0 ] ; then - printf >&2 'vex: Need a command\n' - exit 2 -fi -"$@" -ex=$? -case $ex in - 0) op='true' ;; - *) op='false' ;; -esac -printf '%s\n' "$op" -exit "$ex" diff --git a/bin/vex.sh b/bin/vex.sh new file mode 100644 index 00000000..8a696577 --- /dev/null +++ b/bin/vex.sh @@ -0,0 +1,13 @@ +# Run a command and print a string to stdout showing pass/fail +if [ "$#" -eq 0 ] ; then + printf >&2 'vex: Need a command\n' + exit 2 +fi +"$@" +ex=$? +case $ex in + 0) op='true' ;; + *) op='false' ;; +esac +printf '%s\n' "$op" +exit "$ex" diff --git a/bin/wro b/bin/wro deleted file mode 100755 index 4c465adb..00000000 --- a/bin/wro +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# Add an email-style quote header to input -self=wro - -# Check arguments -if [ "$#" -gt 2 ] ; then - printf >&2 '%s: Too many arguments\n' "$self" - exit 2 -fi - -# Check first argument for the person to quote; if blank, try to form a -# reasonable-looking name from the system -if [ -n "$1" ] ; then - from=$1 -else - un=$(id -nu) - if [ -f /etc/mailname ] ; then - read -r hn < /etc/mailname - else - hn=$(uname -n) - fi - from="$un"@"$hn" -fi - -# Check second argument for the date; if blank, get the system date in whatever -# format it cares to give us -date=${2:-"$(date)"} - -# Print the header and then the input -printf 'On %s, %s wrote:\n' "$date" "$from" -cat diff --git a/bin/wro.sh b/bin/wro.sh new file mode 100644 index 00000000..3888c526 --- /dev/null +++ b/bin/wro.sh @@ -0,0 +1,30 @@ +# Add an email-style quote header to input +self=wro + +# Check arguments +if [ "$#" -gt 2 ] ; then + printf >&2 '%s: Too many arguments\n' "$self" + exit 2 +fi + +# Check first argument for the person to quote; if blank, try to form a +# reasonable-looking name from the system +if [ -n "$1" ] ; then + from=$1 +else + un=$(id -nu) + if [ -f /etc/mailname ] ; then + read -r hn < /etc/mailname + else + hn=$(uname -n) + fi + from="$un"@"$hn" +fi + +# Check second argument for the date; if blank, get the system date in whatever +# format it cares to give us +date=${2:-"$(date)"} + +# Print the header and then the input +printf 'On %s, %s wrote:\n' "$date" "$from" +cat diff --git a/bin/xgo b/bin/xgo deleted file mode 100755 index 652d5a14..00000000 --- a/bin/xgo +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# Test and open a clipboard URL with an apt program - -# Check arguments -if [ "$#" -eq 0 ] ; then - printf >&2 'xgo: At least one URL required\n' -fi - -# Iterate over the URL arguments -for url ; do ( - - # Look for patterns in the URL that suggest transformations - case $url in - - # If this is a GitHub or GitLab link, swap "blob" for "raw" to get the actual file - (*://github.com/*/blob/*|*://gitlab.com/*/blob/*) - url=$(printf '%s\n' "$url" | sed 's_/blob/_/raw/_') - ;; - - # Dig out the plain text for pastebin.com links - (*://pastebin.com/*) - # shellcheck disable=SC2016 - url=$(printf '%s\n' "$url" | sed 's_/[A-Za-z0-9][A-Za-z0-9]*$_/raw&_') - ;; - - # If this is a not-direct imgur link and not to an album, swap URL - # elements to get to the actual file (it may not actually be a JPEG; - # the MIME type will tell us) - (*://imgur.com/a/*) ;; - (*://imgur.com/*) - url=$(printf '%s\n' "$url" | sed 's_imgur\.com_i.imgur.com_;s/$/.jpg/') - ;; - - # If this is a YouTube video without a given start time, load it in mpv(1) - (*[/.]youtube.com/watch*[?\&]t=) ;; - (*[/.]youtube.com/watch*) - mpv -- "$url" && exit - ;; - esac - - # Get the MIME type data - mt=$(urlmt "$url") - - # Switch on media type - case $mt in - - # Open PDFs in xpdf(1); download them first as xpdf(1) does not seem to - # have a way to handle stdin files - (application/pdf) - ( - cd -- "$HOME"/Downloads || exit - curl -O -- "$url" || exit - xpdf -- "${url##*/}" - ) && exit - ;; - - # Open audio and video in mpv(1); force a window even for audio so I - # can control it - (audio/*|video/*) - mpv --force-window -- "$url" && exit - ;; - - # If the MIME type is an image that is not a GIF, load it in feh(1) - (image/gif) ;; - (image/*) - curl -- "$url" | feh - && exit - ;; - - # Open plain text in a terminal view(1) - (text/plain) - # shellcheck disable=SC2016 - urxvt -e sh -c 'curl -- "$1" | view -' _ "$url" && exit - ;; - esac - - # Otherwise, just pass it to br(1df) - br "$url" - -) & done diff --git a/bin/xgo.sh b/bin/xgo.sh new file mode 100644 index 00000000..4d7cf922 --- /dev/null +++ b/bin/xgo.sh @@ -0,0 +1,78 @@ +# Test and open a clipboard URL with an apt program + +# Check arguments +if [ "$#" -eq 0 ] ; then + printf >&2 'xgo: At least one URL required\n' +fi + +# Iterate over the URL arguments +for url ; do ( + + # Look for patterns in the URL that suggest transformations + case $url in + + # If this is a GitHub or GitLab link, swap "blob" for "raw" to get the actual file + (*://github.com/*/blob/*|*://gitlab.com/*/blob/*) + url=$(printf '%s\n' "$url" | sed 's_/blob/_/raw/_') + ;; + + # Dig out the plain text for pastebin.com links + (*://pastebin.com/*) + # shellcheck disable=SC2016 + url=$(printf '%s\n' "$url" | sed 's_/[A-Za-z0-9][A-Za-z0-9]*$_/raw&_') + ;; + + # If this is a not-direct imgur link and not to an album, swap URL + # elements to get to the actual file (it may not actually be a JPEG; + # the MIME type will tell us) + (*://imgur.com/a/*) ;; + (*://imgur.com/*) + url=$(printf '%s\n' "$url" | sed 's_imgur\.com_i.imgur.com_;s/$/.jpg/') + ;; + + # If this is a YouTube video without a given start time, load it in mpv(1) + (*[/.]youtube.com/watch*[?\&]t=) ;; + (*[/.]youtube.com/watch*) + mpv -- "$url" && exit + ;; + esac + + # Get the MIME type data + mt=$(urlmt "$url") + + # Switch on media type + case $mt in + + # Open PDFs in xpdf(1); download them first as xpdf(1) does not seem to + # have a way to handle stdin files + (application/pdf) + ( + cd -- "$HOME"/Downloads || exit + curl -O -- "$url" || exit + xpdf -- "${url##*/}" + ) && exit + ;; + + # Open audio and video in mpv(1); force a window even for audio so I + # can control it + (audio/*|video/*) + mpv --force-window -- "$url" && exit + ;; + + # If the MIME type is an image that is not a GIF, load it in feh(1) + (image/gif) ;; + (image/*) + curl -- "$url" | feh - && exit + ;; + + # Open plain text in a terminal view(1) + (text/plain) + # shellcheck disable=SC2016 + urxvt -e sh -c 'curl -- "$1" | view -' _ "$url" && exit + ;; + esac + + # Otherwise, just pass it to br(1df) + br "$url" + +) & done diff --git a/bin/xgoc b/bin/xgoc deleted file mode 100755 index 516f7028..00000000 --- a/bin/xgoc +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# Run xgo(1df) with the contents of the X clipboard -xgo "$(xsel)" diff --git a/bin/xgoc.sh b/bin/xgoc.sh new file mode 100644 index 00000000..42e04e2d --- /dev/null +++ b/bin/xgoc.sh @@ -0,0 +1,2 @@ +# Run xgo(1df) with the contents of the X clipboard +xgo "$(xsel)" diff --git a/bin/xrbg b/bin/xrbg deleted file mode 100755 index 801bf078..00000000 --- a/bin/xrbg +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Apply a random background image. Requires rndf(1df) and feh(1). -bg=$(rndf "${XBACKGROUNDS:-"$HOME"/.xbackgrounds}") || exit -feh --bg-scale --no-fehbg -- "$bg" diff --git a/bin/xrbg.sh b/bin/xrbg.sh new file mode 100644 index 00000000..617a9b43 --- /dev/null +++ b/bin/xrbg.sh @@ -0,0 +1,3 @@ +# Apply a random background image. Requires rndf(1df) and feh(1). +bg=$(rndf "${XBACKGROUNDS:-"$HOME"/.xbackgrounds}") || exit +feh --bg-scale --no-fehbg -- "$bg" diff --git a/games/aaf b/games/aaf deleted file mode 100755 index 4f1825c6..00000000 --- a/games/aaf +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -curl http://www.asciiartfarts.com/random.cgi | -pup -p 'table[cellpadding]' pre text{} diff --git a/games/aaf.sh b/games/aaf.sh new file mode 100644 index 00000000..4f1825c6 --- /dev/null +++ b/games/aaf.sh @@ -0,0 +1,3 @@ +#!/bin/sh +curl http://www.asciiartfarts.com/random.cgi | +pup -p 'table[cellpadding]' pre text{} diff --git a/games/dr b/games/dr deleted file mode 100755 index e1db163d..00000000 --- a/games/dr +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# Roll D&D-style dice in a ndn+n formula, e.g. 10d6+2 - -# Need exactly one argument -[ "$#" -eq 1 ] || exit 2 - -# Arcane string chopping -n=1 a=0 -nd=${1%+*} -d=${nd#*d} -[ "${nd%d*}" != "" ] && n=${nd%d*} -[ "${1#*+}" = "$1" ] || a=${1#*+} - -# Check number of roles and addendum make sense -[ "$((n > 0 && a >= 0))" -eq 1 ] || exit 2 - -# Check this is a real die you can actually roll -case $d in - 4|6|8|10|12|20) : ;; - *) exit 2 ;; -esac - -# Roll the dice the appropriate number of times using rndi(1df) -i=0 t=0 -while [ "$i" -lt "$n" ] ; do - seed=$(rnds) - r=$(rndi 1 "$d" "$seed") - t=$((t + r)) - i=$((i + 1)) -done - -# Add the addendum -t=$((t + a)) - -# Print it -printf '%u\n' "$t" diff --git a/games/dr.sh b/games/dr.sh new file mode 100644 index 00000000..e1db163d --- /dev/null +++ b/games/dr.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Roll D&D-style dice in a ndn+n formula, e.g. 10d6+2 + +# Need exactly one argument +[ "$#" -eq 1 ] || exit 2 + +# Arcane string chopping +n=1 a=0 +nd=${1%+*} +d=${nd#*d} +[ "${nd%d*}" != "" ] && n=${nd%d*} +[ "${1#*+}" = "$1" ] || a=${1#*+} + +# Check number of roles and addendum make sense +[ "$((n > 0 && a >= 0))" -eq 1 ] || exit 2 + +# Check this is a real die you can actually roll +case $d in + 4|6|8|10|12|20) : ;; + *) exit 2 ;; +esac + +# Roll the dice the appropriate number of times using rndi(1df) +i=0 t=0 +while [ "$i" -lt "$n" ] ; do + seed=$(rnds) + r=$(rndi 1 "$d" "$seed") + t=$((t + r)) + i=$((i + 1)) +done + +# Add the addendum +t=$((t + a)) + +# Print it +printf '%u\n' "$t" diff --git a/games/rndn b/games/rndn deleted file mode 100755 index 18c34218..00000000 --- a/games/rndn +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# Esoteric random number generator - -# Single optional argument is a random seed, otherwise use rnds(1df) -s=${1:-"$(rnds)"} - -# Validate s -case $s in - *[!0-9]*) - printf >&2 'rndn: Seed must be non-negative integer\n' - exit 2 - ;; -esac - -# Helper functions -t() { - printf %u "$1" | cut -c -"$2" -} -l() { - printf %u "$1" | wc -c -} -c() { - printf %u "$1" | cut -c "$2" -} - -# Apply algorithm; you are not expected to understand this -s=$(t "$((s + 10))" 32) i=1 t=0 -while [ "$i" -le "$(l "$s")" ] ; do - d=$(c "$s" "$i") - t=$((t + d)) i=$((i + 1)) -done -p=$((s - t)) -while [ "$(l "$p")" -gt 1 ] ; do - j=1 q=0 - while [ "$j" -le "$(l "$p")" ] ; do - d=$(c "$p" "$j") - q=$((q + d)) j=$((j + 1)) - done - p=$q -done - -# Print result -printf '%u\n' "$p" diff --git a/games/rndn.sh b/games/rndn.sh new file mode 100644 index 00000000..18c34218 --- /dev/null +++ b/games/rndn.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Esoteric random number generator + +# Single optional argument is a random seed, otherwise use rnds(1df) +s=${1:-"$(rnds)"} + +# Validate s +case $s in + *[!0-9]*) + printf >&2 'rndn: Seed must be non-negative integer\n' + exit 2 + ;; +esac + +# Helper functions +t() { + printf %u "$1" | cut -c -"$2" +} +l() { + printf %u "$1" | wc -c +} +c() { + printf %u "$1" | cut -c "$2" +} + +# Apply algorithm; you are not expected to understand this +s=$(t "$((s + 10))" 32) i=1 t=0 +while [ "$i" -le "$(l "$s")" ] ; do + d=$(c "$s" "$i") + t=$((t + d)) i=$((i + 1)) +done +p=$((s - t)) +while [ "$(l "$p")" -gt 1 ] ; do + j=1 q=0 + while [ "$j" -le "$(l "$p")" ] ; do + d=$(c "$p" "$j") + q=$((q + d)) j=$((j + 1)) + done + p=$q +done + +# Print result +printf '%u\n' "$p" diff --git a/games/xyzzy b/games/xyzzy deleted file mode 100755 index d262c0e6..00000000 --- a/games/xyzzy +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -if [ -e "$HOME"/.xyzzy ] ; then - printf >&2 '%s\n' 'Nothing happens.' - exit 1 -fi -printf '%s\n' 'I see no cave here.' > "$HOME"/.xyzzy diff --git a/games/xyzzy.sh b/games/xyzzy.sh new file mode 100644 index 00000000..d262c0e6 --- /dev/null +++ b/games/xyzzy.sh @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -e "$HOME"/.xyzzy ] ; then + printf >&2 '%s\n' 'Nothing happens.' + exit 1 +fi +printf '%s\n' 'I see no cave here.' > "$HOME"/.xyzzy diff --git a/lint/bin b/lint/bin index 1130e432..ff7de0b7 100755 --- a/lint/bin +++ b/lint/bin @@ -1,11 +1,2 @@ #!/bin/sh -for bin in bin/* ; do - [ -f "$bin" ] || continue - hb=$(sed 1q "$bin") || exit - case $hb in - *sh) - printf '%s\n' "$bin" - shellcheck -- "$bin" - ;; - esac -done +find bin -type f -name '*.sh' -print -exec shellcheck -e SC1090 -s sh -- {} + diff --git a/lint/games b/lint/games index ef451f4e..38299a7f 100755 --- a/lint/games +++ b/lint/games @@ -1,11 +1,2 @@ #!/bin/sh -for game in games/* ; do - [ -f "$game" ] || continue - hb=$(sed 1q "$game") || exit - case $hb in - *sh) - printf '%s\n' "$game" - shellcheck -- "$game" - ;; - esac -done +find games -type f -name '*.sh' -print -exec shellcheck -e SC1090 -s sh -- {} + -- cgit v1.2.3