diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2016-08-19 23:22:51 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2016-08-19 23:22:51 +1200 |
commit | 6daae9a75afa12f929be810a52ad21139233adfa (patch) | |
tree | 409f8935029dca341ee4809581d375bd3a42cae4 | |
parent | Merge branch 'master' into freebsd (diff) | |
parent | Update documentation for br(1) and xgo(1) (diff) | |
download | dotfiles-6daae9a75afa12f929be810a52ad21139233adfa.tar.gz dotfiles-6daae9a75afa12f929be810a52ad21139233adfa.zip |
Merge branch 'master' into freebsd
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | ISSUES.markdown | 24 | ||||
-rw-r--r-- | Makefile | 160 | ||||
-rw-r--r-- | README.markdown | 110 | ||||
-rw-r--r-- | bash/bash_completion.d/man.bash | 4 | ||||
-rw-r--r-- | bash/bash_profile | 16 | ||||
-rw-r--r-- | bash/bashrc | 38 | ||||
-rw-r--r-- | bash/bashrc.d/cd.bash | 32 | ||||
-rw-r--r-- | bash/bashrc.d/grep.bash | 33 | ||||
-rw-r--r-- | bash/bashrc.d/keychain.bash | 4 | ||||
-rw-r--r-- | bash/bashrc.d/lhn.bash | 7 | ||||
-rw-r--r-- | bash/bashrc.d/ls.bash | 20 | ||||
-rw-r--r-- | bash/bashrc.d/prompt.bash | 14 | ||||
-rw-r--r-- | bash/bashrc.d/scp.bash | 10 | ||||
-rw-r--r-- | bash/bashrc.d/scr.bash | 12 | ||||
-rw-r--r-- | bash/bashrc.d/vim.bash | 15 | ||||
-rwxr-xr-x | bin/apf | 80 | ||||
-rwxr-xr-x | bin/dmp | 11 | ||||
-rwxr-xr-x | bin/edda | 63 | ||||
-rwxr-xr-x | bin/eds | 86 | ||||
-rwxr-xr-x | bin/fgscr | 2 | ||||
-rwxr-xr-x | bin/han | 22 | ||||
-rwxr-xr-x | bin/plmu | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | bin/rfct.awk (renamed from bin/rfct) | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | bin/rndi.awk (renamed from bin/rndi) | 1 | ||||
-rwxr-xr-x | bin/rndl | 6 | ||||
-rwxr-xr-x | bin/shb | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | bin/slsf.awk (renamed from bin/slsf) | 1 | ||||
-rwxr-xr-x | bin/stws | 2 | ||||
-rwxr-xr-x | bin/td | 6 | ||||
-rwxr-xr-x | bin/tlcs | 3 | ||||
-rwxr-xr-x | bin/try | 5 | ||||
-rwxr-xr-x | bin/urlc | 7 | ||||
-rwxr-xr-x | bin/urlh | 2 | ||||
-rwxr-xr-x | bin/urlmt | 8 | ||||
-rwxr-xr-x | bin/xgo | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | bin/xgoc | 0 | ||||
-rwxr-xr-x | check/bash (renamed from test/bash) | 0 | ||||
-rwxr-xr-x | check/bin (renamed from test/bin) | 2 | ||||
-rwxr-xr-x | check/games (renamed from test/games) | 2 | ||||
-rwxr-xr-x | check/man (renamed from test/man) | 7 | ||||
-rwxr-xr-x | check/pdksh (renamed from test/pdksh) | 0 | ||||
-rwxr-xr-x | check/sh (renamed from test/sh) | 2 | ||||
-rwxr-xr-x | check/urxvt (renamed from test/urxvt) | 0 | ||||
-rw-r--r-- | dircolors/dircolors | 117 | ||||
-rw-r--r-- | games/kvlt.sed | 6 | ||||
-rwxr-xr-x | games/rndn | 82 | ||||
-rw-r--r-- | git/gitconfig.m4 | 5 | ||||
-rw-r--r-- | man/man1/apf.1 | 74 | ||||
-rw-r--r-- | man/man1/br.1 | 12 | ||||
-rw-r--r-- | man/man1/dmp.1 | 14 | ||||
-rw-r--r-- | man/man1/edda.1 | 10 | ||||
-rw-r--r-- | man/man1/unf.1 | 2 | ||||
-rw-r--r-- | man/man1/xgo.1 | 8 | ||||
-rw-r--r-- | man/man7/dotfiles.7.header | 1 | ||||
-rw-r--r-- | pdksh/pdkshrc | 5 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/diff.pdksh | 4 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/ed.pdksh | 26 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/gdb.pdksh | 4 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/gpg.pdksh | 10 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/keychain.pdksh | 4 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/mkcd.pdksh | 4 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/prompt.pdksh | 7 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/pwgen.pdksh | 8 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/rcsdiff.pdksh | 4 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/scp.pdksh | 9 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/sudo.pdksh | 7 | ||||
-rw-r--r-- | pdksh/pdkshrc.d/tmux.pdksh | 19 | ||||
-rw-r--r-- | sh/profile | 13 | ||||
-rw-r--r-- | sh/profile.d/editor.sh | 7 | ||||
-rw-r--r-- | sh/profile.d/env.sh | 10 | ||||
-rw-r--r-- | sh/profile.d/grep.sh | 30 | ||||
-rw-r--r-- | sh/profile.d/ls.sh | 34 | ||||
-rw-r--r-- | sh/profile.d/pager.sh | 2 | ||||
-rw-r--r-- | sh/profile.d/visual.sh | 3 | ||||
-rw-r--r-- | sh/shrc | 12 | ||||
-rw-r--r-- | sh/shrc.d/bc.sh (renamed from bash/bashrc.d/bc.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/cd.sh | 72 | ||||
-rw-r--r-- | sh/shrc.d/diff.sh (renamed from bash/bashrc.d/diff.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/ed.sh (renamed from bash/bashrc.d/ed.bash) | 4 | ||||
-rw-r--r-- | sh/shrc.d/env.sh | 8 | ||||
-rw-r--r-- | sh/shrc.d/gdb.sh (renamed from bash/bashrc.d/gdb.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/gpg.sh (renamed from bash/bashrc.d/gpg.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/grep.sh | 35 | ||||
-rw-r--r-- | sh/shrc.d/hgrep.sh (renamed from bash/bashrc.d/hgrep.bash) | 8 | ||||
-rw-r--r-- | sh/shrc.d/keychain.sh | 3 | ||||
-rw-r--r-- | sh/shrc.d/ksh.sh | 10 | ||||
-rw-r--r-- | sh/shrc.d/ls.sh | 15 | ||||
-rw-r--r-- | sh/shrc.d/mkcd.sh (renamed from bash/bashrc.d/mkcd.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/mysql.sh (renamed from bash/bashrc.d/mysql.bash) | 6 | ||||
-rw-r--r-- | sh/shrc.d/pwgen.sh (renamed from bash/bashrc.d/pwgen.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/rcsdiff.sh (renamed from bash/bashrc.d/rcsdiff.bash) | 0 | ||||
-rw-r--r-- | sh/shrc.d/scp.sh | 14 | ||||
-rw-r--r-- | sh/shrc.d/scr.sh (renamed from pdksh/pdkshrc.d/scr.pdksh) | 7 | ||||
-rw-r--r-- | sh/shrc.d/sudo.sh (renamed from bash/bashrc.d/sudo.bash) | 4 | ||||
-rw-r--r-- | sh/shrc.d/tmux.sh (renamed from bash/bashrc.d/tmux.bash) | 2 | ||||
-rw-r--r-- | sh/shrc.d/vim.sh (renamed from pdksh/pdkshrc.d/vim.pdksh) | 4 | ||||
m--------- | vim/bundle/abolish | 0 | ||||
m--------- | vim/bundle/targets | 0 | ||||
-rw-r--r-- | vim/vimrc | 2 | ||||
-rw-r--r-- | zsh/zprofile | 6 | ||||
-rw-r--r-- | zsh/zshrc | 12 |
102 files changed, 728 insertions, 877 deletions
@@ -1,4 +1,7 @@ +bin/rfct +bin/rndi bin/sd2u +bin/slsf bin/su2d bin/unf games/acq diff --git a/ISSUES.markdown b/ISSUES.markdown index a94cf846..68c6c482 100644 --- a/ISSUES.markdown +++ b/ISSUES.markdown @@ -8,22 +8,14 @@ Known issues * man(1) completion doesn't work on OpenBSD as manpath(1) isn't a thing on that system; need to find some way of finding which manual directories should be searched at runtime, if there is one. -* mktemp(1) is not POSIX, though it's commonly available; where a temporary - file is unavoidable, it might be nice to abstract this with a wrapper - script that uses mktemp(1) if it can, but otherwise uses mkdir(1) with a - randomised name in "${TMPDIR:-/tmp}". Is mktemp(1) on every *BSD? - - Mostly fixed now with mktd(1), still using mktemp(1) in a few places -* Where practical, the remaining Bash scripts in bin need to be reimplemented - as POSIX sh - - Mostly done now: - - [tom@conan:~/.dotfiles/bin](git:master)$ grep bash * - apf:#!/usr/bin/env bash - edda:#!/usr/bin/env bash - eds:#!/usr/bin/env bash - han:#!/usr/bin/env bash - jfcd:#!/usr/bin/env bash - * OpenBSD doesn't have a `pandoc` package at all. It would be nice to find some way of converting the README.markdown into a palatable troff format with some more readily available (and preferably less heavyweight) tool. +* At least one of the completion scripts (pass.bash) hangs on empty + completions (i.e. nothing matches the search term) in Bash 4.4rc1; the last + thing bash -x shows is an "exit 1" hang +* The checks gscr(1) makes to determine where it is are a bit naive (don't + work with bare repos) and could probably be improved with some appropriate + git-reflog(1) cals +* The \xFF syntax for regex as used in rfct(1) is not POSIX. Need to decide + if it's well-supported enough to keep it anyway. @@ -8,7 +8,6 @@ install-bin \ install-bin-man \ install-curl \ - install-dircolors \ install-dotfiles-man \ install-dunst \ install-finger \ @@ -42,12 +41,12 @@ install-wyrd \ install-x \ install-zsh \ - test \ - test-bash \ - test-bin \ - test-games \ - test-sh \ - test-urxvt \ + check \ + check-bash \ + check-bin \ + check-games \ + check-sh \ + check-urxvt \ lint \ lint-bash \ lint-bin \ @@ -55,16 +54,28 @@ lint-sh \ lint-urxvt +.SUFFIXES: .awk .sed + NAME := Tom Ryder EMAIL := tom@sanctum.geek.nz KEY := 0xC14286EA77BB8872 SENDMAIL := /usr/bin/msmtp -all : bin/sd2u bin/su2d bin/unf git/gitconfig gnupg/gpg.conf +all : bin/rfct \ + bin/rndi \ + bin/sd2u \ + bin/slsf \ + bin/su2d \ + bin/unf \ + git/gitconfig \ + gnupg/gpg.conf clean distclean : rm -f \ + bin/rfct \ + bin/rndi \ bin/sd2u \ + bin/slsf \ bin/su2d \ bin/unf \ games/acq \ @@ -76,30 +87,6 @@ clean distclean : mutt/muttrc \ tmux/tmux.conf -bin/sd2u : bin/sd2u.sed - bin/shb bin/sd2u.sed sed -f > "$@" - chmod +x "$@" - -bin/su2d : bin/su2d.sed - bin/shb bin/su2d.sed sed -f > "$@" - chmod +x "$@" - -bin/unf : bin/unf.sed - bin/shb bin/unf.sed sed -f > "$@" - chmod +x "$@" - -games/acq : games/acq.sed - bin/shb games/acq.sed sed -f > "$@" - chmod +x "$@" - -games/kvlt : games/kvlt.sed - bin/shb games/kvlt.sed sed -f > "$@" - chmod +x "$@" - -games/zs : games/zs.sed - bin/shb games/zs.sed sed -f > "$@" - chmod +x "$@" - git/gitconfig : git/gitconfig.m4 m4 \ -D DOTFILES_NAME="$(NAME)" \ @@ -127,11 +114,18 @@ tmux/tmux.conf : tmux/tmux.conf.m4 m4 -D TMUX_COLOR="$(TMUX_COLOR)" \ tmux/tmux.conf.m4 > tmux/tmux.conf +.awk : + bin/shb "$<" awk -f > "$@" + chmod +x "$@" + +.sed : + bin/shb "$<" sed -f > "$@" + chmod +x "$@" + install : install-bash \ install-bash-completion \ install-bin \ install-curl \ - install-dircolors \ install-git \ install-gnupg \ install-readline \ @@ -144,7 +138,7 @@ install-abook : "$(HOME)"/.abook install -pm 0644 -- abook/abookrc "$(HOME)"/.abook -install-bash : test-bash +install-bash : check-bash install-sh install -m 0755 -d -- \ "$(HOME)"/.config \ "$(HOME)"/.bashrc.d \ @@ -160,13 +154,11 @@ install-bash-completion : install-bash install -pm 0644 -- bash/bash_completion "$(HOME)"/.config/bash_completion install -pm 0644 -- bash/bash_completion.d/* "$(HOME)"/.bash_completion.d -install-bin : bin/sd2u bin/su2d bin/unf test-bin install-bin-man +install-bin : bin/sd2u bin/su2d bin/unf check-bin install-bin-man install -m 0755 -d -- "$(HOME)"/.local/bin for name in bin/* ; do \ - case $$name in \ - *.sed) ;; \ - *) install -m 0755 -- "$$name" "$(HOME)"/.local/bin ;; \ - esac \ + [ -x "$$name" ] || continue ; \ + install -m 0755 -- "$$name" "$(HOME)"/.local/bin ; \ done install-bin-man : @@ -179,9 +171,6 @@ install-bin-man : install-curl : install -pm 0644 -- curl/curlrc "$(HOME)"/.curlrc -install-dircolors : - install -pm 0644 -- dircolors/dircolors "$(HOME)"/.dircolors - install-dotfiles-man : man/man7/dotfiles.7 install -m 0755 -d -- "$(HOME)"/.local/share/man/man7 install -pm 0644 -- man/man7/*.7 "$(HOME)"/.local/share/man/man7 @@ -195,13 +184,11 @@ install-finger : install -pm 0644 -- finger/project "$(HOME)"/.project install -pm 0644 -- finger/pgpkey "$(HOME)"/.pgpkey -install-games : games/acq games/kvlt games/zs test-games install-games-man +install-games : games/acq games/kvlt games/zs check-games install-games-man install -m 0755 -d -- "$(HOME)"/.local/games - for game in games/* ; do \ - case $$game in \ - *.sed) ;; \ - *) install -m 0755 -- "$$game" "$(HOME)"/.local/games ;; \ - esac \ + for name in games/* ; do \ + [ -x "$$name" ] || continue ; \ + install -m 0755 -- "$$name" "$(HOME)"/.local/games ; \ done install-games-man : @@ -229,12 +216,6 @@ install-i3 : install-x install -m 0755 -d -- "$(HOME)"/.i3 install -pm 0644 -- i3/* "$(HOME)"/.i3 -install-pdksh : test-pdksh install-sh - install -m 0755 -d -- \ - "$(HOME)"/.pdkshrc.d - install -pm 0644 -- pdksh/pdkshrc "$(HOME)"/.pdkshrc - install -pm 0644 -- pdksh/pdkshrc.d/* "$(HOME)"/.pdkshrc.d - install-maildir : install -m 0755 -d -- \ "$(HOME)"/Mail/inbox/cur \ @@ -264,6 +245,12 @@ install-newsbeuter : install-mysql : install -pm 0644 -- mysql/my.cnf "$(HOME)"/.my.cnf +install-pdksh : check-pdksh install-sh + install -m 0755 -d -- \ + "$(HOME)"/.pdkshrc.d + install -pm 0644 -- pdksh/pdkshrc "$(HOME)"/.pdkshrc + install -pm 0644 -- pdksh/pdkshrc.d/* "$(HOME)"/.pdkshrc.d + install-perlcritic : install -pm 0644 -- perlcritic/perlcriticrc "$(HOME)"/.perlcriticrc @@ -276,10 +263,14 @@ install-psql : install-readline : install -pm 0644 -- readline/inputrc "$(HOME)"/.inputrc -install-sh : test-sh - install -m 0755 -d -- "$(HOME)"/.profile.d +install-sh : check-sh + install -m 0755 -d -- \ + "$(HOME)"/.profile.d \ + "$(HOME)"/.shrc.d install -pm 0644 -- sh/profile "$(HOME)"/.profile install -pm 0644 -- sh/profile.d/* "$(HOME)"/.profile.d + install -pm 0644 -- sh/shrc "$(HOME)"/.shrc + install -pm 0644 -- sh/shrc.d/* "$(HOME)"/.shrc.d install-subversion : install -m 0755 -d -- "$(HOME)"/.subversion @@ -294,7 +285,7 @@ install-terminfo : install-tmux : tmux/tmux.conf install -pm 0644 -- tmux/tmux.conf "$(HOME)"/.tmux.conf -install-urxvt : test-urxvt +install-urxvt : check-urxvt install -m 0755 -d -- "$(HOME)"/.urxvt/ext install -m 0755 -- urxvt/ext/* "$(HOME)"/.urxvt/ext @@ -312,24 +303,11 @@ install-gvim-config : install -pm 0644 -- vim/gvimrc "$(HOME)"/.gvimrc install-vim-plugins : install-vim-config - install -m 0755 -d -- "$(HOME)"/.vim/bundle - find vim/bundle -name .git -prune -o \ - \( -type d -print \) | \ - while IFS= read -r dir ; do \ - install -m 0755 -d -- \ - "$$dir" "$(HOME)"/.vim/"$${dir#vim/}" ; \ - done - find vim/bundle -name .git -prune -o \ - \( -type f ! -name '.git*' -print \) | \ - while IFS= read -r file ; do \ - install -pm 0644 -- \ - "$$file" "$(HOME)"/.vim/"$${file#vim/}" ; \ - done - for dir in vim/after/* ; do \ - install -m 0755 -d -- "$(HOME)"/.vim/after/"$${dir##*/}" ; \ - install -pm 0644 -- "$$dir"/* \ - "$(HOME)"/.vim/after/"$${dir##*/}" ; \ - done + find vim/after vim/bundle -name .git -prune -o \ + -type d -exec sh -c 'install -m 0755 -d -- \ + "$(HOME)"/.vim/"$${1#vim/}"' _ {} \; -o \ + -type f -exec sh -c 'install -m 0644 -- \ + "$$1" "$(HOME)"/.vim/"$${1#vim/}"' _ {} \; install-vim-pathogen : install-vim-plugins install -m 0755 -d -- "$(HOME)"/.vim/autoload @@ -350,32 +328,32 @@ install-x : install -pm 0644 -- X/Xresources "$(HOME)"/.Xresources install -pm 0644 -- X/Xresources.d/* "$(HOME)"/.Xresources.d -install-zsh : +install-zsh : install-sh install -pm 0644 -- zsh/zprofile "$(HOME)"/.zprofile install -pm 0644 -- zsh/zshrc "$(HOME)"/.zshrc -test : test-bash test-bin test-games test-man test-sh test-urxvt +check : check-bash check-bin check-games check-man check-sh check-urxvt -test-bash : - test/bash +check-bash : + check/bash -test-bin : - test/bin +check-bin : + check/bin -test-games : - test/games +check-games : + check/games -test-pdksh : - test/pdksh +check-pdksh : + check/pdksh -test-man : - test/man +check-man : + check/man -test-sh : - test/sh +check-sh : + check/sh -test-urxvt : - test/urxvt +check-urxvt : + check/urxvt lint : lint-bash lint-bin lint-games lint-sh lint-urxvt diff --git a/README.markdown b/README.markdown index 191371f4..47197122 100644 --- a/README.markdown +++ b/README.markdown @@ -47,8 +47,6 @@ Configuration is included for: shells * [cURL](https://curl.haxx.se/) -- Command-line tool for transferring data with URL syntax -* [`dircolors(1)`](https://www.gnu.org/software/coreutils/manual/html_node/dircolors-invocation.html) - -- Color GNU `ls(1)` output * [Dunst](http://knopwob.org/dunst/) -- A lightweight X11 notification daemon that works with `libnotify` * `finger(1)` -- User information lookup program @@ -83,7 +81,7 @@ Configuration is included for: frontend for [Remind](https://www.roaringpenguin.com/products/remind) * [X11](https://www.x.org/wiki/) -- Windowing system with network transparency for Unix -* [Zsh](http://www.zsh.org/) -- Bourne-style shell designed for interactive +* [Zsh](https://www.zsh.org/) -- Bourne-style shell designed for interactive use The configurations for Bash, GnuPG, Mutt, tmux, and Vim are the most expansive @@ -133,21 +131,22 @@ defaults for interactive behavior. A terminal session with my prompt looks something like this: - [tom@conan:~/.dotfiles](git:master+!)$ git status + tom@conan:~/.dotfiles(master+!)$ git status M README.markdown M bash/bashrc.d/prompt.bash A init - [tom@conan:~/.dotfiles](git:master+!)$ foobar + tom@conan:~/.dotfiles(master+!)$ foobar foobar: command not found - [tom@conan:~/.dotfiles](git:master+!)<127>$ sleep 5 & + tom@conan:~/.dotfiles(master+!)<127>$ sleep 5 & [1] 28937 - [tom@conan:~/.dotfiles](git:master+!){1}$ + tom@conan:~/.dotfiles(master+!){1}$ It expands based on context to include these elements in this order: * Whether in a Git repository if applicable, and punctuation to show whether there are local modifications at a glance; Subversion support can also be - enabled (I need it at work) + enabled (I need it at work), in which case a `git:` or `svn:` prefix is + added appropriately * The number of running background jobs, if non-zero * The exit status of the last command, if non-zero @@ -160,6 +159,65 @@ common terminals using both `termcap(5)` and `terminfo(5)`, including \*BSD systems. It's also designed to degrade gracefully for eight-color and no-color terminals. +#### Functions + +If a function can be written in POSIX `sh` without too much hackery, I put it +in `sh/shrc.d` to be loaded by any POSIX interactive shell. Those include: + +* `bc()` silences startup messages from GNU `bc(1)`. +* `diff()` forces the unified format for `diff(1)`. +* `cd()` wraps the `cd` builtin to allow for a second parameter for string + substitution, emulating a Zsh function I like. +* `ed()` tries to get verbose error messages, a prompt, and a Readline + environment for `ed(1)`. +* `env()` sorts the output of `env(1)` if it was invoked with no arguments, + because the various shells have different ways of listing exported + variables. +* `gdb()` silences startup messages from `gdb(1)`. +* `gpg()` quietens `gpg(1)` down for most commands. +* `hgrep()` allows searching `$HISTFILE`. +* `keychain()` updates `$GPG_TTY` if set for `keychain(1)`. +* `mkcd()` creates a directory and changes into it. +* `mysql()` allows shortcuts to MySQL configuration files stored in + `~/.mysql`. +* `pwgen()` generates just one decent password with `pwgen(1)`. +* `rcsdiff()` forces a unified format for `rcsdiff(1)`. +* `scp()` tries to detect forgotten hostnames in `scp(1)` command calls. +* `scr()` creates a temporary directory and changes into it. +* `sudo()` forces `-H` for `sudo(8)` calls so that `$HOME` is never + preserved; I hate ending up `root`-owned files in my home directory. +* `tmux()` changes the default command for `tmux(1)` to `attach-session -d` + if a session exists, or creates a new session if one doesn't. +* `vim()` defines three functions to always use `vim(1)` as my `ex(1)`, + `vi(1)` and `view(1)` implementation if it's available. + +There are a few other little tricks defined for other shells, mostly in +`bash/bashrc.d`: + +* `bd()` changes into a named ancestor of the current directory. +* `fnl()` runs a command and saves its output and error into temporary files, + defining variables with the filenames in them. +* `grep()` tries to apply color and other options good for interactive use, + depending on the capabilities of the system `grep(1)`. It's dependent on + information written by the `grep.sh` script in `~/.profile.d`. +* `keep()` stores ad-hoc shell functions and variables. +* `lhn()` gets the history number of the last command. +* `ls()` tries to apply color to `ls(1)` for interactive use if available. + It's dependent on information written by the `ls.sh` script in + `~/.profile.d`. +* `path()` manages the contents of `PATH` conveniently. +* `pd()` changes to the argument's parent directory. +* `prompt()` sets up my interactive prompt. +* `pushd()` adds a default destination of `$HOME` to the `pushd` builtin. +* `readv()` prints names and values from `read` calls to `stderr`. +* `readz()` is an alias for `read -d '' -r`. +* `sd()` changes into a sibling of the current directory. +* `ud()` changes into an indexed ancestor of a directory. +* `vared()` allows interactively editing a variable with Readline, emulating + a Zsh function I like by the same name. +* `vr()` tries to change to the root directory of a source control + repository. + #### Completion I find the `bash-completion` package a bit too heavy for my tastes, and turn it @@ -182,28 +240,6 @@ files for things I really do get tired of typing repeatedly: I also add completions for my own scripts and functions where useful. -#### Functions - -There are a few other little tricks in `bash/bashrc.d`, including: - -* `bd()` changes into a named ancestor of the current directory. -* `fnl()` runs a command and save its output and error into temporary files. -* `hgrep()` searches `$HISTFILE`. -* `keep()` stores ad-hoc shell functions and variables. -* `mkcd()` creates a directory and changes into it. -* `path()` manages the contents of `PATH` conveniently. -* `pd()` changes to the argument's parent directory. -* `readv()` prints names and values from `read` calls to `stderr`. -* `readz()` is an alias for `read -d '' -r`. -* `scr()` creates a temporary directory and changes into it. -* `sd()` changes into a sibling of the current directory. -* `ud()` changes into an indexed ancestor of a directory. - -I also wrap a few command calls with functions to stop me from doing silly -things that the commands themselves don't catch. My favourite is the one that -stops me from calling `scp(1)` with no colon in either argument. I also do -things like give default arguments to `pwgen(1)`. - #### pdksh The pdksh configuration files and functions are not nearly as featureful as the @@ -211,6 +247,11 @@ Bash ones. They're tested on OpenBSD and FreeBSD pdksh implementations, but the former is the primary system for which I'm maintaining them, and there are some feature differences. +#### Zsh + +These are experimental; I do not like Zsh much at the moment. The files started +as a joke (`exec bash`). + ### GnuPG The configuration for GnuPG is intended to follow [RiseUp's OpenPGP best @@ -339,7 +380,7 @@ Installed by the `install-bin` target: for unfolding HTTP headers, but it should work for most RFC 822 formats. * `apf(1)` prepends arguments to a command with ones read from a file, - intended as a framework for shell functions. + intended as a framework for shell wrappers or functions. * `ax(1)` evaluates an awk expression given on the command line; this is intended as a quick way to test how Awk would interpret a given expression. * `bel(1)` prints a terminal bell character. @@ -422,9 +463,10 @@ your `/etc/manpath` configuration, depending on your system. Testing ------- -You can test that both sets of shell scripts are syntactically correct with -`make test-bash`, `make test-sh`, or `make test` for everything including the -scripts in `bin` and `games`. +You can check that both sets of shell scripts are syntactically correct with +`make check-bash`, `make check-sh`, or `make check` for everything including +the scripts in `bin` and `games`. There's no proper test suite for the actual +functionality (yet). If you have [ShellCheck](https://www.shellcheck.net/) and/or [Perl::Critic](http://perlcritic.com/), there's a `lint` target for the shell diff --git a/bash/bash_completion.d/man.bash b/bash/bash_completion.d/man.bash index f1762a01..d2499c0a 100644 --- a/bash/bash_completion.d/man.bash +++ b/bash/bash_completion.d/man.bash @@ -35,8 +35,8 @@ _man() { # Iterate through the manual page paths and add every manual page we find for manpath in "${manpaths[@]}" ; do - [[ $manpath ]] || continue - if [[ $section ]] ; then + [[ -n $manpath ]] || continue + if [[ -n $section ]] ; then for page in "$manpath"/"$subdir"/"$word"*."$section"?(.[glx]z|.bz2|.lzma|.Z) ; do pages[${#pages[@]}]=$page done diff --git a/bash/bash_profile b/bash/bash_profile index ee735720..db1d9bc8 100644 --- a/bash/bash_profile +++ b/bash/bash_profile @@ -14,16 +14,12 @@ elif ((BASH_VERSINFO[0] == 2)) && fi # Load any supplementary scripts -if [[ -d $HOME/.bash_profile.d ]] ; then - for bash_profile in "$HOME"/.bash_profile.d/*.bash ; do - if [[ -e $bash_profile ]] ; then - source "$bash_profile" - fi - done - unset -v bash_profile -fi +for sh in "$HOME"/.bash_profile.d/*.bash ; do + [[ -e $sh ]] && source "$sh" +done +unset -v sh -# Source interactive Bash config if it exists -if [[ -e $HOME/.bashrc ]] ; then +# If ~/.bashrc exists, source that too; the test for interactivity is in there +if [[ -f $HOME/.bashrc ]] ; then source "$HOME"/.bashrc fi diff --git a/bash/bashrc b/bash/bashrc index b551819d..7defd85d 100644 --- a/bash/bashrc +++ b/bash/bashrc @@ -8,21 +8,22 @@ elif ((BASH_VERSINFO[0] == 2)) && return fi -# Don't do anything if not running interactively -if [[ $- != *i* ]] ; then - return -fi +# Make sure the shell is interactive +case $- in + *i*) ;; + *) return ;; +esac # Don't do anything if running a restricted shell if shopt -q restricted_shell ; then return fi -# Keep around sixteen million lines of history in file -HISTFILESIZE=$((1 << 24)) +# Keep around four thousand lines of history in file +HISTFILESIZE=$((1 << 12)) -# Keep around four thousand lines of history in memory -HISTSIZE=$((1 << 12)) +# Keep around one thousand lines of history in memory +HISTSIZE=$((1 << 10)) # Ignore duplicate commands and whitespace in history HISTCONTROL=ignoreboth @@ -101,20 +102,15 @@ fi # If COMP_WORDBREAKS has a value, strip all colons from it; this allows # completing filenames correctly, since an unquoted colon is not a syntactic # character: <http://tiswww.case.edu/php/chet/bash/FAQ> (E13) -if [[ $COMP_WORDBREAKS ]] ; then +if [[ -n $COMP_WORDBREAKS ]] ; then COMP_WORDBREAKS=${COMP_WORDBREAKS//:} fi -# Load any supplementary scripts -for bashrc in "$HOME"/.bashrc.d/*.bash ; do - [[ -e $bashrc ]] || continue - source "$bashrc" -done -unset -v bashrc - -# Load any completion files -for bashcmp in "$HOME"/.bash_completion.d/*.bash ; do - [[ -e $bashcmp ]] || continue - source "$bashcmp" +# Load POSIX shell functions, Bash-specific scripts, and Bash completion files, +# in that order +for sh in "$ENV" \ + "$HOME"/.bashrc.d/*.bash \ + "$HOME"/.bash_completion.d/*.bash ; do + [[ -e $sh ]] && source "$sh" done -unset -v bashcmp +unset -v sh diff --git a/bash/bashrc.d/cd.bash b/bash/bashrc.d/cd.bash deleted file mode 100644 index 04de96d5..00000000 --- a/bash/bashrc.d/cd.bash +++ /dev/null @@ -1,32 +0,0 @@ -# If given two arguments to cd, replace the first with the second in $PWD, -# emulating a Zsh function that I often find useful; preserves options too -cd() { - local arg - local -a opts - for arg ; do - case $arg in - --) - shift - break - ;; - -*) - shift - opts[${#opts[@]}]=$arg - ;; - *) - break - ;; - esac - done - if (($# == 2)) ; then - if [[ $PWD == *"$1"* ]] ; then - builtin cd "${opts[@]}" -- "${PWD/"$1"/"$2"}" - else - printf 'bash: %s: could not replace substring\n' \ - "$FUNCNAME" >&2 - return 2 - fi - else - builtin cd "${opts[@]}" -- "$@" - fi -} diff --git a/bash/bashrc.d/grep.bash b/bash/bashrc.d/grep.bash deleted file mode 100644 index 11eeb5b0..00000000 --- a/bash/bashrc.d/grep.bash +++ /dev/null @@ -1,33 +0,0 @@ -# Store whether we have colors in a variable -declare -i colors -colors=$( { - tput Co || tput colors -} 2>/dev/null ) - -# Store grep(1)'s --help output in a variable -grep_help=$(grep --help 2>/dev/null) - -# Use GREPOPTS to add some useful options to grep(1) calls if applicable; we -# use a function wrapper to do this, rather than GREP_OPTIONS as we don't want -# to change grep(1)'s actual behaviour inside scripts -declare -a GREPOPTS -if [[ -n $GREP_COLORS ]] && ((colors >= 8)) ; then - GREPOPTS[${#GREPOPTS[@]}]='--color=auto' -fi -if [[ $grep_help == *--binary-files* ]] ; then - GREPOPTS[${#GREPOPTS[@]}]='--binary-files=without-match' -fi -if [[ $grep_help == *--exclude* ]] ; then - GREPOPTS[${#GREPOPTS[@]}]='--exclude={.gitignore,.gitmodules}' -fi -if [[ $grep_help == *--exclude-dir* ]] ; then - GREPOPTS[${#GREPOPTS[@]}]='--exclude-dir={.cvs,.git,.hg,.svn}' -fi - -# Done, unset helper vars -unset -v grep_help colors - -# Define function proper -grep() { - command grep "${GREPOPTS[@]}" "$@" -} diff --git a/bash/bashrc.d/keychain.bash b/bash/bashrc.d/keychain.bash deleted file mode 100644 index 40fe5d71..00000000 --- a/bash/bashrc.d/keychain.bash +++ /dev/null @@ -1,4 +0,0 @@ -# If GPG_TTY is set, update it -if [[ -n $GPG_TTY ]] ; then - GPG_TTY=$(tty) -fi diff --git a/bash/bashrc.d/lhn.bash b/bash/bashrc.d/lhn.bash new file mode 100644 index 00000000..89c6f5da --- /dev/null +++ b/bash/bashrc.d/lhn.bash @@ -0,0 +1,7 @@ +# Print the history number of the last command +lhn () { + local last + last=$(fc -l -1) || return + [[ -n $last ]] || return + printf '%u\n' "${last%%[^0-9]*}" +} diff --git a/bash/bashrc.d/ls.bash b/bash/bashrc.d/ls.bash deleted file mode 100644 index 4b647163..00000000 --- a/bash/bashrc.d/ls.bash +++ /dev/null @@ -1,20 +0,0 @@ -# Store whether we have colors in a variable -declare -i colors -colors=$( { - tput Co || tput colors -} 2>/dev/null ) - -# Use LSOPTS to add some useful options to ls(1) calls if applicable; we use a -# function wrapper to do this -declare -a LSOPTS -if [[ -n $LS_COLORS ]] && ((colors >= 8)) ; then - LSOPTS[${#LSOPTS[@]}]='--color=auto' -fi - -# Done, unset helper var -unset -v colors - -# Define function proper -ls() { - command ls "${LSOPTS[@]}" "$@" -} diff --git a/bash/bashrc.d/prompt.bash b/bash/bashrc.d/prompt.bash index b5ac74b1..081cff69 100644 --- a/bash/bashrc.d/prompt.bash +++ b/bash/bashrc.d/prompt.bash @@ -24,7 +24,7 @@ prompt() { fi # Basic prompt shape - PS1='[\u@\h:\w]' + PS1='\u@\h:\w' # Add sub-commands; VCS, job, and return status checks PS1=$PS1'$(prompt vcs)$(prompt job)$(prompt ret)' @@ -104,6 +104,13 @@ prompt() { return 1 fi + # Bail if we're not in a work tree + local iswt + iswt=$(git rev-parse --is-inside-work-tree 2>/dev/null) + if [[ $iswt != true ]] ; then + return 1 + fi + # Attempt to determine git branch, bail if we can't local branch branch=$( { @@ -130,8 +137,9 @@ prompt() { state=${state}^ fi - # Print the status in brackets with a git: prefix - printf '(git:%s%s)' "${branch:-unknown}" "$state" + # Print the status in brackets; add a git: prefix only if there + # might be another VCS prompt (because PROMPT_VCS is set) + printf '(%s%s%s)' "${PROMPT_VCS:+git:}" "${branch:-unknown}" "$state" ;; # Subversion prompt function diff --git a/bash/bashrc.d/scp.bash b/bash/bashrc.d/scp.bash deleted file mode 100644 index cd2f8521..00000000 --- a/bash/bashrc.d/scp.bash +++ /dev/null @@ -1,10 +0,0 @@ -# Wrap scp(1) to check for missing colons -scp() { - # shellcheck disable=SC2048 - if (($# >= 2)) && [[ $* != *:* ]] ; then - printf 'bash: %s: Missing colon, probably an error\n' \ - "$FUNCNAME" >&2 - return 2 - fi - command scp "$@" -} diff --git a/bash/bashrc.d/scr.bash b/bash/bashrc.d/scr.bash deleted file mode 100644 index bf2990fd..00000000 --- a/bash/bashrc.d/scr.bash +++ /dev/null @@ -1,12 +0,0 @@ -# Create a temporary directory and change into it, to stop me putting stray -# files into $HOME, and making the system do cleanup for me. Single optional -# argument is the string to use for naming the directory; defaults to "scr". -scr() { - if (($# <= 1)) ; then - pushd -- "$(mktd "${1:-"$FUNCNAME"}")" - else - printf 'bash: %s: too many arguments\n' \ - "$FUNCNAME" >&2 - return 2 - fi -} diff --git a/bash/bashrc.d/vim.bash b/bash/bashrc.d/vim.bash deleted file mode 100644 index 37fc1871..00000000 --- a/bash/bashrc.d/vim.bash +++ /dev/null @@ -1,15 +0,0 @@ -# If Vim exists on the system, use it instead of ex, vi, and view -if ! hash vim 2>/dev/null ; then - return -fi - -# Define functions proper -ex() { - vim -e "$@" -} -vi() { - vim "$@" -} -view() { - vim -R "$@" -} @@ -1,43 +1,55 @@ -#!/usr/bin/env bash -# Prepend arguments from a file to a command call +#!/bin/sh +# Prepend arguments from a file to the given arguments for a command self=apf -# Require at least two arguments, give usage otherwise -if (($# < 2)) ; then - printf '%s: usage: %s ARGFILE COMMAND [ARGS...]\n' \ - "$self" "$self" >&2 +# 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 -argfile=$1 -shift - -# Check the arguments file makes sense -if [[ ! -e $argfile ]] ; then - printf '%s: %s: No such file or directory\n' \ - "$self" "$argfile" - exit 1 -elif [[ -d $argfile ]] ; then - printf '%s: %s: Is a directory\n' \ - "$self" "$argfile" - exit 1 -elif [[ ! -r $argfile ]] ; then - printf '%s: %s: Permission denied\n' \ - "$self" "$argfile" - exit 1 -fi +argf=$1 cmd=$2 +shift 2 + +# If the file exists, we'll read it. If it doesn't, this is not an error (think +# personal config files like ~/.vimrc) +if [ -f "$argf" ] ; 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 -# Read all the null-delimited arguments from the file -declare -a args -while IFS= read -rd '' arg ; do - args[${#args[@]}]=$arg -done < "$argfile" + # Write the arguments in reverse to a temporary file + revf=$td/revf + sed '1!G;$!{h;d}' "$argf" > "$revf" || exit -# Next argument is the command to run -cmd=$1 -shift + # Stack up all the arguments from the file. Skip blank lines and comments. + # An empty file is also fine. + while IFS= read -r arg ; do + case $arg in + '#'*) continue ;; + *[![:space:]]*) ;; + *) continue ;; + esac + set -- "$arg" "$@" + done < "$revf" + + # We can remove the temporary stuff now, which allows us to exec safely + cleanup +fi -# Run the command with the retrieved arguments first, then the rest of the -# command line as passed to the function -command "$cmd" "${args[@]}" "$@" +# Run the command with the changed arguments +exec "$cmd" "$@" @@ -1,11 +1,15 @@ #!/bin/sh +# Sole optional argument is the password timeout (defaults to 10 seconds) +timeout_sec=${1:-10} + # 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) @@ -13,10 +17,7 @@ pw=$( # Sort them sort | # Strip the leading directory and the trailing .gpg - sed ' -s_^\./__ -s_\.gpg$__ - ' | + sed 's_^\./__;s_\.gpg$__' | # Use dmenu(1) to prompt the user to select one dmenu ) || exit @@ -25,4 +26,4 @@ s_\.gpg$__ [ -n "$pw" ] || exit # Pump the password into the clipboard xsel(2); allow 10 seconds -pass show "$pw" | xsel -ibt 10000 +pass show "$pw" | xsel -ibt "$((timeout_sec * 1000))" @@ -1,50 +1,33 @@ -#!/usr/bin/env bash +#!/bin/sh # Run ed(1) over multiple files, duplicating stdin. -self=edda - -# Define usage function -usage() { - printf 'USAGE: %s [OPTS] [--] FILE1 [FILE2...]\n' "$self" -} # Need at least one file -if ! (($#)) ; then - usage >&2 - exit 1 +if [ "$#" -eq 0 ] ; then + printf >&2 'edda: Need at least one file\n' + exit 2 fi -# Need ed(1) -- some systems daring to call themselves UNIX-like don't have it -# installed by default. What's POSIX, precious? -hash ed || exit - -# Parse options out, give help if necessary -declare -a opts -for arg ; do - case $arg in - --help|-h|-\?) - usage - exit - ;; - --) - shift - break - ;; - -*) - shift - opts[${#opts[@]}]=$arg - ;; - esac -done - -# Duplicate stdin into a file, which we'll remove on exit -stdin=$(mktemp -t "$self".XXXXXX) || exit +# Create a temporary directory with name in $td, and handle POSIX-ish traps to +# remove it when the script exits. +td= cleanup() { - rm -f -- "$stdin" + [ -n "$td" ] && rm -fr -- "$td" + if [ "$1" != EXIT ] ; then + trap - "$1" + kill "-$1" "$$" + fi } -trap cleanup EXIT -cat > "$stdin" +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 options and stdin given +# Run ed(1) over each file with the stdin given for file ; do - ed "${opts[@]}" -- "$file" < "$stdin" + ed -- "$file" <"$script" done @@ -1,64 +1,52 @@ -#!/usr/bin/env bash +#!/bin/sh # Create and edit executable scripts in a directory EDSPATH (defaults to ~/.local/bin) -self=eds -# Define a function to show usage -usage() { - printf 'USAGE: %s [EDITOR_OPTS] [--] FILE1 [FILE2...]\n' \ - "$self" -} +# 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 -# Process options, including detecting requests for help -declare -a opts +# 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 - --help|-h|-\?) - usage - exit 0 - ;; --) - shift - break + optend=1 + set -- "$@" "$arg" + continue ;; -*) - shift - opts[${#opts[@]}]=$arg - ;; - *) - break + if [ -z "$optend" ] ; then + set -- "$@" "$arg" + continue + fi ;; esac + optend=1 + set -- "$@" "$ep"/"$arg" done -# If no arguments left, spit usage as an error and bail -if ! (($#)) ; then - usage >&2 - exit 1 -fi - -# Create the script directory if it doesn't exist yet -edspath=${EDSPATH:-$HOME/.local/bin} -if [[ ! -d $edspath ]] ; then - mkdir -p -- "$edspath" || exit -fi - -# Create a new array with the script directory prepended to the given names -declare -a files -files=("${@/#/$edspath/}") - -# Collect the names of any scripts that don't exist yet so we can make them -# executable after we're done editing -declare -a creations -for file in "${files[@]}" ; do - [[ -e $file ]] && continue - creations[${#creations[@]}]=$file -done - -# Run the editor; if EDITOR isn't set, use vi(1) -"${EDITOR:-vi}" "${opts[@]}" -- "${files[@]}" +# Run the editor over the arguments +echo "${VISUAL:-"${EDITOR:-ed}"}" "$@" +exit # Make any created scripts executable if they now appear to be files -for creation in "${creations[@]}" ; do - [[ -f $creation ]] || continue - chmod +x -- "$creation" +for script ; do + [ -f "$script" ] || continue + chmod +x -- "$script" done @@ -2,7 +2,7 @@ # Find all the Git repositories in a directory and scrub them all # Check we have gscr(1) first -command -v gscr >/dev/null || exit +command -v gscr >/dev/null 2>&1 || exit # Look for any dir named .git in the given (default current) dir and run # gscr(1) on it @@ -3,31 +3,31 @@ self=han # Give up completely if no BASH_VERSINFO (<2.0) -if ! [ -n "$BASH_VERSINFO" ] ; then - exit -fi +[ -n "$BASH_VERSINFO" ] || exit # Figure out the options with which we can call help; Bash >=4.0 has an -m -# option which prints the help output in a man-page like format. +# option which prints the help output in a man-page like format declare -a helpopts if ((BASH_VERSINFO[0] >= 4)) ; then helpopts=(-m) fi -# Create a temporary file and set up a trap to get rid of it. -tmpdir=$(mktemp -dt "$self".XXXXXX) || exit +# Create a temporary directory with name in $td, and a trap to remove it when +# the script exits +td= cleanup() { - rm -fr -- "$tmpdir" + [[ -n "$td" ]] && rm -fr -- "$td" } trap cleanup EXIT +td=$(mktd "$self") || exit # If we have exactly one argument and a call to the help builtin with that -# argument succeeds, display its output with `pager -s`. +# argument succeeds, display its output with `pager -s` if (($# == 1)) && - help "${helpopts[@]}" "$1" >"$tmpdir"/"$1".help 2>/dev/null ; then - (cd -- "$tmpdir" && pager -s -- "$1".help) + help "${helpopts[@]}" "$1" >"$td"/"$1".help 2>/dev/null ; then + (cd -- "$td" && "$PAGER" -s -- "$1".help) -# Otherwise, just pass all the arguments to man(1). +# Otherwise, just pass all the arguments to man(1) else man "$@" fi @@ -6,7 +6,7 @@ ef=$HOME/.plenv/non-cpanm-modules # Check that exceptions file is sorted if ! sort -c -- "$ef" ; then - printf '%s not sorted\n' "$ef" >&2 + printf >&2 '%s not sorted\n' "$ef" exit 1 fi diff --git a/bin/rfct b/bin/rfct.awk index dff7a4e2..53e948b2 100755..100644 --- a/bin/rfct +++ b/bin/rfct.awk @@ -1,4 +1,4 @@ -#!/usr/bin/awk -f +# Format an RFC in text format for terminal reading # A record is a paragraph BEGIN { diff --git a/bin/rndi b/bin/rndi.awk index bf78951c..337498cb 100755..100644 --- a/bin/rndi +++ b/bin/rndi.awk @@ -1,4 +1,3 @@ -#!/usr/bin/awk -f # Get a low-quality random number between two integers. Depending on the awk # implementation, if you don't provide a third argument (a seed), you might get # very predictable random numbers based on the current epoch second. @@ -1,5 +1,6 @@ #!/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 @@ -7,7 +8,8 @@ # file if we don't want to read all of the input into memory (!) if [ "$#" -eq 0 ] ; then - # Try to create the temporary directory with mktd(1) safely + # 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" @@ -20,7 +22,7 @@ if [ "$#" -eq 0 ] ; then # shellcheck disable=SC2064 trap "cleanup $sig" "$sig" done - td=$(mktd rndl) || exit + td=$(mktd "$self") || exit # We'll operate on stdin in the temp directory; write the script's stdin to # it with cat(1) @@ -14,7 +14,7 @@ scr=$1 intn=$2 shift 2 # Try and find the path to the interpreter command, bail out if we can't -if ! intp=$(command -v "$intn") ; then +if ! intp=$(command -v "$intn" 2>/dev/null) ; then printf >&2 '%s: %s: command not found\n' "$self" "$intn" exit 1 fi diff --git a/bin/slsf b/bin/slsf.awk index 6824ec13..9d12225d 100755..100644 --- a/bin/slsf +++ b/bin/slsf.awk @@ -1,4 +1,3 @@ -#!/usr/bin/awk -f # Print the first non-glob "Host" name from each line of ssh_config(5) files # Manage the processing flag (starts set in each file) @@ -3,7 +3,7 @@ # Check arguments if [ "$#" -eq 0 ] ; then - printf >&2 'tstf: Need a filename\n' + printf >&2 'stws: Need a filename\n' exit 2 fi @@ -12,7 +12,7 @@ file=${1:-"${TODO_NAME:-todo}"} cd -- "$dir" || exit # If the current directory isn't a Git repository, try to create one -if ! command -v isgr >/dev/null ; then +if ! command -v isgr >/dev/null 2>&1 ; then printf >&2 'isgr: command not found\n' exit 1 fi @@ -21,8 +21,8 @@ isgr || git init || exit # If the to-do file doesn't exist yet, create it [ -e "$file" ] || touch -- "$file" || exit -# Launch $VISUAL (or $EDITOR (or vi(1))) to edit the appropriate to-do file -"${VISUAL:-"${EDITOR:-vi}"}" "$file" +# Launch an appropriate editor to edit that file +"${VISUAL:-"${EDITOR:-ed}"}" "$file" # Add the file to the changeset git add -- "$file" @@ -67,7 +67,8 @@ if [ "$((color_count >= 8))" -eq 1 ] ; then fi fi -# Temporary directory for the FIFOs +# 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" @@ -26,7 +26,8 @@ if [ "$#" -eq 0 ] ; then exit 2 fi -# Create a buffer file for the error output, and clean up the file when we exit +# 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" @@ -40,9 +41,9 @@ for sig in EXIT HUP INT TERM ; do trap "cleanup $sig" "$sig" done td=$(mktd "$self") || exit -errbuff=$td/errbuff # 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 @@ -5,8 +5,8 @@ self=urlc # cURL request timeout tm=${URLCHECK_TIMEOUT:-8} -# Create buffer files for the headers and body content, to be cleaned up on -# exit +# 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" @@ -20,6 +20,9 @@ for sig in EXIT HUP INT TERM ; do 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 @@ -12,7 +12,7 @@ url=$1 header=$2 curl -I -- "$url" | # Unfold the headers -unf | +unf | # Change the line endings to UNIX format sd2u | @@ -1,3 +1,9 @@ #!/bin/sh # Get the MIME type for a given URL -urlh "$1" Content-Type | sed 's/; .*//' +urlh "$1" Content-Type | + +# Use last line only, remove any charset suffix +sed ' +$!d +s/; .*// +' @@ -11,23 +11,23 @@ for url ; do ( # If it's a YouTube video without a given start time, load it in mpv(1) case $url in - *youtube.com/watch*[?\&]t=) ;; - *youtube.com/watch*) - mpv -- "$url" && continue + *[/.]youtube.com/watch*[?\&]t=) ;; + *[/.]youtube.com/watch*) + mpv -- "$url" && exit ;; esac + # Get the MIME type data + mt=$(urlmt "$url") + # If the MIME type is an image, load it in feh(1) case $mt in image/gif) ;; image/*) - curl -- "$url" | feh - && continue + curl -- "$url" | feh - && exit ;; esac - # Get the MIME type data - mt=$(urlmt "$url") - # Otherwise, just pass it to br(1) br "$url" ) & done @@ -1,6 +1,6 @@ #!/bin/sh for bin in bin/* ; do - [ -f "$bin" ] || continue + [ -x "$bin" ] || continue hb=$(sed 1q "$bin") || exit case $hb in *bash) diff --git a/test/games b/check/games index 3afe6414..d3b5feac 100755 --- a/test/games +++ b/check/games @@ -1,6 +1,6 @@ #!/bin/sh for game in games/* ; do - [ -f "$game" ] || continue + [ -x "$game" ] || continue hb=$(sed 1q "$game") || exit case $hb in *bash) @@ -35,15 +35,18 @@ comm -13 "$td"/bin "$td"/man > "$td"/nobin # Emit the content of both, if any ex=0 if [ -s "$td"/noman ] ; then - printf >&2 '%s\n' 'No manual pages found for:' + printf >&2 'No manual pages found for:\n' cat >&2 -- "$td"/noman ex=1 fi if [ -s "$td"/nobin ] ; then - printf >&2 '%s\n' 'Stray manual page for:' + printf >&2 'Stray manual page for:\n' cat >&2 -- "$td"/nobin ex=1 fi # Exit appropriately +if [ "$ex" -eq 0 ] ; then + printf 'All scripts have manual pages.\n' +fi exit "$ex" diff --git a/test/pdksh b/check/pdksh index fd1d55b7..fd1d55b7 100755 --- a/test/pdksh +++ b/check/pdksh @@ -1,5 +1,5 @@ #!/bin/sh -for sh in sh/* sh/profile.d/* ; do +for sh in sh/* sh/profile.d/* sh/shrc.d/* ; do [ -f "$sh" ] || continue sh -n "$sh" || exit done diff --git a/test/urxvt b/check/urxvt index d27d6660..d27d6660 100755 --- a/test/urxvt +++ b/check/urxvt diff --git a/dircolors/dircolors b/dircolors/dircolors deleted file mode 100644 index 2b583feb..00000000 --- a/dircolors/dircolors +++ /dev/null @@ -1,117 +0,0 @@ -TERM ansi -TERM linux -TERM putty -TERM putty-256color -TERM rxvt -TERM rxvt-256color -TERM rxvt-unicode -TERM rxvt-unicode-256color -TERM screen -TERM screen-256color -TERM xterm -TERM xterm-256color -DIR 01;34 -LINK 01;36 -FIFO 40;33 -SOCK 01;35 -DOOR 01;35 -BLK 40;33;01 -CHR 40;33;01 -ORPHAN 40;31;01 -EXEC 01;32 -.tar 01;31 -.tgz 01;31 -.arj 01;31 -.taz 01;31 -.lzh 01;31 -.lzma 01;31 -.tlz 01;31 -.txz 01;31 -.zip 01;31 -.z 01;31 -.Z 01;31 -.dz 01;31 -.gz 01;31 -.lz 01;31 -.xz 01;31 -.bz2 01;31 -.bz 01;31 -.tbz 01;31 -.tbz2 01;31 -.tz 01;31 -.deb 01;31 -.rpm 01;31 -.jar 01;31 -.war 01;31 -.ear 01;31 -.sar 01;31 -.rar 01;31 -.ace 01;31 -.zoo 01;31 -.cpio 01;31 -.7z 01;31 -.rz 01;31 -.jpg 01;35 -.jpeg 01;35 -.gif 01;35 -.bmp 01;35 -.pbm 01;35 -.pgm 01;35 -.ppm 01;35 -.tga 01;35 -.xbm 01;35 -.xpm 01;35 -.tif 01;35 -.tiff 01;35 -.png 01;35 -.svg 01;35 -.svgz 01;35 -.mng 01;35 -.pcx 01;35 -.mov 01;35 -.mpg 01;35 -.mpeg 01;35 -.m2v 01;35 -.mkv 01;35 -.webm 01;35 -.ogm 01;35 -.mp4 01;35 -.m4v 01;35 -.mp4v 01;35 -.vob 01;35 -.qt 01;35 -.nuv 01;35 -.wmv 01;35 -.asf 01;35 -.rm 01;35 -.rmvb 01;35 -.flc 01;35 -.avi 01;35 -.fli 01;35 -.flv 01;35 -.gl 01;35 -.dl 01;35 -.xcf 01;35 -.xwd 01;35 -.yuv 01;35 -.cgm 01;35 -.emf 01;35 -.axv 01;35 -.anx 01;35 -.ogv 01;35 -.ogx 01;35 -.aac 00;36 -.au 00;36 -.flac 00;36 -.mid 00;36 -.midi 00;36 -.mka 00;36 -.mp3 00;36 -.mpc 00;36 -.ogg 00;36 -.ra 00;36 -.wav 00;36 -.axa 00;36 -.oga 00;36 -.spx 00;36 -.xspf 00;36 diff --git a/games/kvlt.sed b/games/kvlt.sed index 1cb06b5a..f90eab2f 100644 --- a/games/kvlt.sed +++ b/games/kvlt.sed @@ -8,6 +8,9 @@ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ s/^/~/ s/$/~/ +# All numbers become 666 +s,[0-9][0-9]*,666,g + # Various words for KVLT s,\([^A-Z]\)ASSOCIATION\([^A-Z]\),\1KVLT\2,g s,\([^A-Z]\)BUSINESS\([^A-Z]\),\1KVLT\2,g @@ -66,9 +69,6 @@ s,\([^A-Z]\)AND\([^A-Z]\),\1VND\2,g # TRUE -> TRV s,\([^A-Z]\)TRUE\([^A-Z]\),\1TRV\2,g -# All numbers become 666 -s,[0-9][0-9]*,666,g - # Remove the padding established above s/^~// s/~$// @@ -1,59 +1,43 @@ -#!/usr/bin/env bash - +#!/bin/sh # Esoteric random number generator -# <http://dilbert.com/strip/2001-10-25> -self=rndn - -# Define usage function -usage() { - printf 'USAGE: %s [-h | -s SEED]\n' "$self" -} -# Parse options -while getopts 'hs:' opt ; do - case $opt in +# Single optional argument is a random seed, otherwise use rnds(1) +s=${1:-"$(rnds)"} - # -h for help - h) - usage - exit 0 - ;; - - # -s to set seed manually - s) - seed=$OPTARG - ;; - - # Unknown option, print usage and fail - \?) - usage >&2 - exit 2 - ;; - esac -done -shift "$((OPTIND-1))" +# Validate s +case $s in + *[!0-9]*) + printf >&2 'rndn: Seed must be non-negative integer\n' + exit 2 + ;; +esac -# If no seed given, get one from Bash's $RANDOM -: "${seed:=$((RANDOM ** 2))}" - -# Truncate the seed -seed=${seed:0:32} - -# Check seed meets algorithm conditions -if [[ $seed == *[^0-9]* ]] || ((seed < 0)) ; then - printf >&2 '%s: error: seed must be non-negative integer\n' "$self" - exit 2 -fi +# Helper functions +t() { + printf %u "$1" | cut -c -"$2" +} +l() { + printf %u "$1" | wc -c +} +c() { + printf %u "$1" | cut -c "$2" +} -# Apply algorithm -for ((seed += 10, i = 0; i < ${#seed}; i++)) ; do - ((sum += ${seed:i:1})) +# 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 -for ((red = seed - sum; ${#red} > 1; red = redn)) ; do - for ((j = 0, redn = 0; j < ${#red}; j++)) ; do - ((redn += ${red:j:1})) +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' "$red" +printf '%u\n' "$p" diff --git a/git/gitconfig.m4 b/git/gitconfig.m4 index 616fdad8..73bdae98 100644 --- a/git/gitconfig.m4 +++ b/git/gitconfig.m4 @@ -1,5 +1,7 @@ [advice] statusHints = false + detachedHead = false + pushUpdateRejected = false [alias] others = ls-files --others --exclude-standard @@ -24,6 +26,9 @@ [merge] ff = false +[pull] + ff = only + [push] default = current diff --git a/man/man1/apf.1 b/man/man1/apf.1 index 67b3b25a..7cb2ab28 100644 --- a/man/man1/apf.1 +++ b/man/man1/apf.1 @@ -7,30 +7,34 @@ foorc foo --bar baz .SH DESCRIPTION -Add null-delimited arguments read from a file to a command's arguments before -running it. This is intended as a way of implementing *rc files for interactive -shell calls to programs that don't support such files, without having to use -broken environment variables (e.g. GREP_OPTIONS); this enables you to, for -example, use arguments with shell metacharacters and spaces in them that you do -not want expanded. - +Add newline-delimited arguments read from a file to a command's arguments +(before any given ones) before running it. This is intended as a quick way of +implementing *rc files for interactive shell calls to programs that don't +support such files, without having to use broken environment variables like GNU +grep(1)'s GREP_OPTIONS. +.P +This enables you to use arguments with shell metacharacters and spaces in them +that you do not want expanded. The only exception is that you cannot have +newlines in any of the arguments. This was done to keep POSIX sh(1) +compatibility. +.P For example, given this simple program in our $PATH, printargs: - - $ cat ~/.local/bin/printargs +.P + $ cat /usr/bin/printargs #!/bin/sh - printf '%s\n' "$@" - + printf '%s\\n' "$@" +.P Which just prints its arguments: - +.P $ printargs a b c a b c - +.P We could do this: - - $ printf '%s\0' -f --flag --option '? foo bar *' > "$HOME"/.printargsrc - +.P + $ printf '%s\\n' -f --flag --option '? foo bar *' > "$HOME"/.printargsrc +.P $ apf "$HOME"/.printargsrc printargs a b c -f --flag @@ -39,27 +43,23 @@ We could do this: a b c - -We could then make a permanent wrapper function with: - +.P +We could then make a permanent wrapper script in two line: +.P + $ cat >~/.local/bin/printargs + #!/bin/sh + exec apf "$HOME"/.printargsrc /usr/bin/printargs + ^D + $ chmod +x ~/.local/bin/printargs +.P +Or just a shell function, if it's needed interactively: +.P $ printargs() { apf "$HOME"/.printargsrc printargs "$@" ; } - - $ printargs a b c - -f - --flag - --option - ? foo bar * - a - b - c - - $ printf '%s\n' !-2:q >> "$HOME"/.bashrc - -This means you can edit the options in the *rc file, and don't have to redefine -a wrapper function. - -If you actually want those options to *always* be added, regardless of whether -you're in an interactive shell, you really should make an actual wrapper -script. +.P +It's not considered an error if the file doesn't exist or is empty. If it's a +directory or otherwise not byte-readable, an error will be printed to stderr, +but execution of the called program will continue anyway. Blank lines or lines +beginning with # are also ignored. Both leading and trailing whitespace is +preserved. .SH AUTHOR Tom Ryder <tom@sanctum.geek.nz> diff --git a/man/man1/br.1 b/man/man1/br.1 index ad841750..5f6de5f7 100644 --- a/man/man1/br.1 +++ b/man/man1/br.1 @@ -12,14 +12,12 @@ BROWSER=firefox .B br .SH DESCRIPTION .B br -run with no arguments just execs the program in the $BROWSER environment -variable. If given a single URL, it tries to get its MIME type from a HEAD -request and matches on the URL and/or the MIME type to see if any more suitable -programs could open it. Otherwise, it falls back on $BROWSER. +just execs the program in the $BROWSER environment variable with the given +arguments. That's it. .P -At the time of writing, it tries to load image types with feh(1), and YouTube -URLs without a start time with mpv(1). +It was written to have a clean way to launch $BROWSER from ~/.xbindkeysrc. It +has no other reason to exist. .SH SEE ALSO -brxs(1), urlh(1), urlmt(1), feh(1), mpv(1) +xgo(1), xgoc(1) .SH AUTHOR Tom Ryder <tom@sanctum.geek.nz> diff --git a/man/man1/dmp.1 b/man/man1/dmp.1 index 2d9111d6..e9b5dc4f 100644 --- a/man/man1/dmp.1 +++ b/man/man1/dmp.1 @@ -1,15 +1,19 @@ -.TH DMP 1 "May 2014" "Manual page for dmp" +.TH DMP 1 "August 2016" "Manual page for dmp" .SH NAME .B dmp \- pick a pass(1) password with dmenu(1) .SH SYNOPSIS .B dmp +.br +.B dmp 25 .SH DESCRIPTION .B dmp -applies dmenu(1) to pick a password entry -from a pass(1) store and put it into the X -CLIPBOARD for up to 10 seconds. +applies dmenu(1) to pick a password entry from a pass(1) store and put it into +the X CLIPBOARD for up to 10 seconds. +.P +An optional timeout in seconds can be applied, after which xsel(1) will remove +the password from the clipboard. This timeout defaults to 10 seconds. .SH SEE ALSO -dmenu(1), pass(1) +dmenu(1), pass(1), xsel(1) .SH AUTHOR Tom Ryder <tom@sanctum.geek.nz> diff --git a/man/man1/edda.1 b/man/man1/edda.1 index 21e6b163..3123c0ce 100644 --- a/man/man1/edda.1 +++ b/man/man1/edda.1 @@ -1,14 +1,14 @@ -.TH EDDA 1 "June 2015" "Manual page for edda" +.TH EDDA 1 "August 2016" "Manual page for edda" .SH NAME .B edda \- run ed(1) over multiple files .SH SYNOPSIS -.B edda [OPTS] [--] FILE1 [FILE2...] +.B edda FILE1 [FILE2...] .SH DESCRIPTION -Duplicate any data on stdin into a temporary file, and run ed(1) with any given -options over each of the files given as the remaining arguments. Example: +Duplicate any data on stdin into a temporary file, and run ed(1) options over +each of the files given as the remaining arguments. Example: .P - $ edda -s /etc/app.d/*.conf <<EOF + $ edda /etc/app.d/*.conf <<EOF ,s/foo/bar/g w EOF diff --git a/man/man1/unf.1 b/man/man1/unf.1 index 709e7d2b..57d4548f 100644 --- a/man/man1/unf.1 +++ b/man/man1/unf.1 @@ -13,7 +13,7 @@ FILE FILE1 FILE2... .br curl -I http://www.example.net/ | -.B +.B unf .SH DESCRIPTION Joins lines with leading spaces in the output to the previous line, diff --git a/man/man1/xgo.1 b/man/man1/xgo.1 index 13cbdd37..5eec6517 100644 --- a/man/man1/xgo.1 +++ b/man/man1/xgo.1 @@ -6,8 +6,12 @@ .B xgo .SH DESCRIPTION .B xgo -examines each of its arguments and opens an appropriate program to view it, -falling back on $BROWSER. +examines each of its arguments, including making an HTTP HEAD request to try +and get its MIME type, and then opens an appropriate program to view it, +falling back on $BROWSER. The choices of application are very opinionated. +.SH FUTURE +There could probably be a MIME-type and/or URL-pattern to program configuration +file, rather than hard-coding it. .SH SEE ALSO br(1), xgoc(1) .SH AUTHOR diff --git a/man/man7/dotfiles.7.header b/man/man7/dotfiles.7.header index 2731f7dc..b059b0fd 100644 --- a/man/man7/dotfiles.7.header +++ b/man/man7/dotfiles.7.header @@ -1,4 +1,3 @@ % DOTFILES(7) % Tom Ryder % June 2016 - diff --git a/pdksh/pdkshrc b/pdksh/pdkshrc index 46dbba2c..48799c2e 100644 --- a/pdksh/pdkshrc +++ b/pdksh/pdkshrc @@ -4,11 +4,10 @@ set -o emacs # Save history HISTFILE=$HOME/.pdksh_history -HISTSIZE=$((1 << 12)) +HISTSIZE=$((1 << 10)) # Load any supplementary scripts for pdkshrc in "$HOME"/.pdkshrc.d/*.pdksh ; do - [[ -e $pdkshrc ]] || continue - . "$pdkshrc" + [[ -e $pdkshrc ]] && . "$pdkshrc" done unset -v pdkshrc diff --git a/pdksh/pdkshrc.d/diff.pdksh b/pdksh/pdkshrc.d/diff.pdksh deleted file mode 100644 index 2c752c8d..00000000 --- a/pdksh/pdkshrc.d/diff.pdksh +++ /dev/null @@ -1,4 +0,0 @@ -# Use a unified format for diff(1) by default -diff() { - command diff -u "$@" -} diff --git a/pdksh/pdkshrc.d/ed.pdksh b/pdksh/pdkshrc.d/ed.pdksh deleted file mode 100644 index f64f6dc6..00000000 --- a/pdksh/pdkshrc.d/ed.pdksh +++ /dev/null @@ -1,26 +0,0 @@ -# Add a colon prompt to ed when a command is expected rather than text; makes -# it feel a lot more like using ex. Only do this when stdin is a terminal, -# however. Also try and use -v for more verbose error output, and rlwrap(1) if -# it's available. -ed() { - - # We're only adding options if input is from a terminal - if [[ -t 0 ]] ; then - - # Colon prompt (POSIX) - set -- -p : "$@" - - # Verbose if availble (not POSIX) - if ed -sv - </dev/null >&0 2>&0 ; then - set -- -v "$@" - fi - fi - - # Execute the ed(1) call, in a wrapper if appropriate and with the - # concluded options - if [[ -t 0 ]] && command -v rlwrap >/dev/null ; then - command rlwrap ed "$@" - else - command ed "$@" - fi -} diff --git a/pdksh/pdkshrc.d/gdb.pdksh b/pdksh/pdkshrc.d/gdb.pdksh deleted file mode 100644 index ec9d4137..00000000 --- a/pdksh/pdkshrc.d/gdb.pdksh +++ /dev/null @@ -1,4 +0,0 @@ -# Don't print the GDB copyright message on every invocation -gdb() { - command gdb -q "$@" -} diff --git a/pdksh/pdkshrc.d/gpg.pdksh b/pdksh/pdkshrc.d/gpg.pdksh deleted file mode 100644 index 62d123ea..00000000 --- a/pdksh/pdkshrc.d/gpg.pdksh +++ /dev/null @@ -1,10 +0,0 @@ -# Wrapper around gpg(1) to stop ``--batch'' breaking things -gpg() { - # shellcheck disable=SC2048 - case $* in - *--ed*|*--gen-k*|*--sign-k*) - set -- --no-batch "$@" - ;; - esac - command gpg "$@" -} diff --git a/pdksh/pdkshrc.d/keychain.pdksh b/pdksh/pdkshrc.d/keychain.pdksh deleted file mode 100644 index 40fe5d71..00000000 --- a/pdksh/pdkshrc.d/keychain.pdksh +++ /dev/null @@ -1,4 +0,0 @@ -# If GPG_TTY is set, update it -if [[ -n $GPG_TTY ]] ; then - GPG_TTY=$(tty) -fi diff --git a/pdksh/pdkshrc.d/mkcd.pdksh b/pdksh/pdkshrc.d/mkcd.pdksh deleted file mode 100644 index 6342d4a6..00000000 --- a/pdksh/pdkshrc.d/mkcd.pdksh +++ /dev/null @@ -1,4 +0,0 @@ -# Create a directory and change into it -mkcd() { - mkdir -p -- "$1" && builtin cd -- "$1" -} diff --git a/pdksh/pdkshrc.d/prompt.pdksh b/pdksh/pdkshrc.d/prompt.pdksh index c3db782b..71e952a0 100644 --- a/pdksh/pdkshrc.d/prompt.pdksh +++ b/pdksh/pdkshrc.d/prompt.pdksh @@ -17,7 +17,7 @@ prompt() { on) # Set up prompt, including optional PROMPT_PREFIX and PROMPT_SUFFIX # variables - PS1='[\u@\h:\w]' + PS1='\u@\h:\w' PS1=$PS1'$(prompt vcs)' PS1=$PS1'$(prompt job)' PS1='${PROMPT_PREFIX}'$PS1 @@ -111,8 +111,9 @@ prompt() { state=${state}^ fi - # Print the status in brackets with a git: prefix - printf '(git:%s%s)' "${branch:-unknown}" "$state" + # Print the status in brackets; add a git: prefix only if there + # might be another VCS prompt (because PROMPT_VCS is set) + printf '(%s%s%s)' "${PROMPT_VCS:+git:}" "${branch:-unknown}" "$state" ;; # Revert to simple inexpensive prompts diff --git a/pdksh/pdkshrc.d/pwgen.pdksh b/pdksh/pdkshrc.d/pwgen.pdksh deleted file mode 100644 index 7ba056e5..00000000 --- a/pdksh/pdkshrc.d/pwgen.pdksh +++ /dev/null @@ -1,8 +0,0 @@ -# Set some defaults for pwgen(1), because its defaults are to give me a long -# list of relatively short passwords, when I generally want only one good one -pwgen() { - if ! (($#)) ; then - set -- --secure -- "${PWGEN_LENGTH:-15}" "${PWGEN_COUNT:-1}" - fi - command pwgen "$@" -} diff --git a/pdksh/pdkshrc.d/rcsdiff.pdksh b/pdksh/pdkshrc.d/rcsdiff.pdksh deleted file mode 100644 index 18b1d324..00000000 --- a/pdksh/pdkshrc.d/rcsdiff.pdksh +++ /dev/null @@ -1,4 +0,0 @@ -# Use a unified format for rcsdiff(1) by default -rcsdiff() { - command rcsdiff -u "$@" -} diff --git a/pdksh/pdkshrc.d/scp.pdksh b/pdksh/pdkshrc.d/scp.pdksh deleted file mode 100644 index c3565f21..00000000 --- a/pdksh/pdkshrc.d/scp.pdksh +++ /dev/null @@ -1,9 +0,0 @@ -# Wrap scp(1) to check for missing colons -scp() { - # shellcheck disable=SC2048 - if (($# >= 2)) && [[ $* != *:* ]] ; then - printf 'ksh: scp: Missing colon, probably an error\n' >&2 - return 2 - fi - command scp "$@" -} diff --git a/pdksh/pdkshrc.d/sudo.pdksh b/pdksh/pdkshrc.d/sudo.pdksh deleted file mode 100644 index d6d91d12..00000000 --- a/pdksh/pdkshrc.d/sudo.pdksh +++ /dev/null @@ -1,7 +0,0 @@ -# Add the -H parameter to sudo(8) calls, always use the target user's $HOME -sudo() { - if [[ $1 != -v ]] ; then - set -- -H "$@" - fi - command sudo "$@" -} diff --git a/pdksh/pdkshrc.d/tmux.pdksh b/pdksh/pdkshrc.d/tmux.pdksh deleted file mode 100644 index f0d0e36a..00000000 --- a/pdksh/pdkshrc.d/tmux.pdksh +++ /dev/null @@ -1,19 +0,0 @@ -# Attach to existing tmux session rather than create a new one if possible -tmux() { - - # If given any arguments, just use them as they are - if (($#)) ; 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 - command tmux "$@" -} @@ -4,8 +4,13 @@ if [ -d "$HOME"/.local/bin ] ; then fi # Load all supplementary scripts in ~/.profile.d -for profile in "$HOME"/.profile.d/*.sh ; do - [ -e "$profile" ] || continue - . "$profile" +for sh in "$HOME"/.profile.d/*.sh ; do + [ -e "$sh" ] && . "$sh" done -unset -v profile +unset -v sh + +# If ENV is unset after running those scripts and ~/.shrc exists, set it as ENV +if [ -z "$ENV" ] && [ -f "$HOME"/.shrc ] ; then + ENV=$HOME/.shrc + export ENV +fi diff --git a/sh/profile.d/editor.sh b/sh/profile.d/editor.sh index 7ed9e262..ee0da70b 100644 --- a/sh/profile.d/editor.sh +++ b/sh/profile.d/editor.sh @@ -1,4 +1,3 @@ -# Set editor -EDITOR=vi -VISUAL=$EDITOR -export EDITOR VISUAL +# Set command-line editor +EDITOR=ed +export EDITOR diff --git a/sh/profile.d/env.sh b/sh/profile.d/env.sh deleted file mode 100644 index f1b83919..00000000 --- a/sh/profile.d/env.sh +++ /dev/null @@ -1,10 +0,0 @@ -# If we're running some kind of ksh, export ENV to find a suitable startup -# file. Bash differs considerably from this behaviour; it uses ENV as its -# startup file when it's invoked as sh(1), and uses .bashrc or --rcfile as its -# interactive startup file, so it doesn't need to be specified here. -case $KSH_VERSION in - *'PD KSH '*) ENV=$HOME/.pdkshrc ;; -esac -if [ -n "$ENV" ] ; then - export ENV -fi diff --git a/sh/profile.d/grep.sh b/sh/profile.d/grep.sh index 87c9a6cc..892351ca 100644 --- a/sh/profile.d/grep.sh +++ b/sh/profile.d/grep.sh @@ -1,13 +1,21 @@ -# Store grep(1)'s --help output in a variable -grep_help=$(grep --help 2>/dev/null) +# Test that we have metadata about what options this system's grep(1) supports, +# and try to create it if not +( + # Create a directory to hold metadata about grep + gcd=$HOME/.cache/grep + if ! [ -d "$gcd" ] ; then + mkdir -p -- "$gcd" || exit + fi -# Set and export GREP_COLORS if available and appropriate -case $grep_help in - *--color*) - GREP_COLORS='ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36' - export GREP_COLORS - ;; -esac + # Write grep(1)'s --help output to a file, even if it's empty + if ! [ -f "$gcd"/help ] ; then + grep --help </dev/null >"$gcd"/help 2>/dev/null || exit -# We're done parsing grep(1)'s --help output now -unset -v grep_help + # Iterate through some useful options and create files to show they're + # available + for opt in binary-files color exclude exclude-dir ; do + grep -q -- --"$opt" "$gcd"/help || continue + touch -- "$gcd"/"$opt" || exit + done + fi +) diff --git a/sh/profile.d/ls.sh b/sh/profile.d/ls.sh index a3cc84b7..0c3754e9 100644 --- a/sh/profile.d/ls.sh +++ b/sh/profile.d/ls.sh @@ -1,18 +1,20 @@ -# Store ls(1)'s --help output in a variable -ls_help=$(ls --help 2>/dev/null) +# Test that we have metadata about what options this system's ls(1) supports, +# and try to create it if not +( + # Create a directory to hold metadata about ls(1) + lcd=$HOME/.cache/ls + if ! [ -d "$lcd" ] ; then + mkdir -p -- "$lcd" || exit + fi -# Run dircolors(1) to export LS_COLORS if available and appropriate -case $ls_help in - *--color*) - if command -v dircolors >/dev/null 2>&1 ; then - if [ -r "$HOME"/.dircolors ] ; then - eval "$(dircolors --sh -- "$HOME"/.dircolors)" - else - eval "$(dircolors --sh)" - fi - fi - ;; -esac + # Write ls(1)'s --help output to a file, even if it's empty + if ! [ -f "$lcd"/help ] ; then + ls --help >"$lcd"/help 2>/dev/null || exit -# We're done parsing ls(1)'s --help output now -unset -v ls_help + # Iterate through some useful options and create files to show they're + # available + if grep -q -- --color "$lcd"/help ; then + touch -- "$lcd"/color || exit + fi + fi +) diff --git a/sh/profile.d/pager.sh b/sh/profile.d/pager.sh index 2cbcb26d..f0c4fab4 100644 --- a/sh/profile.d/pager.sh +++ b/sh/profile.d/pager.sh @@ -1,6 +1,6 @@ # If we don't have less(1), we'll just use whatever pager the application or # system deems fit -command less >/dev/null 2>&1 || return +command -v less >/dev/null 2>&1 || return # Use less(1) as my PAGER PAGER=less diff --git a/sh/profile.d/visual.sh b/sh/profile.d/visual.sh new file mode 100644 index 00000000..95eb1d5d --- /dev/null +++ b/sh/profile.d/visual.sh @@ -0,0 +1,3 @@ +# Set visual editor +VISUAL=vi +export VISUAL diff --git a/sh/shrc b/sh/shrc new file mode 100644 index 00000000..deb55cc2 --- /dev/null +++ b/sh/shrc @@ -0,0 +1,12 @@ +# Make sure the shell is interactive +case $- in + *i*) ;; + *) return ;; +esac + +# Load all the POSIX-compatible functions from ~/.shrc.d; more advanced shells +# like bash will have their own functions +for sh in "$HOME"/.shrc.d/*.sh ; do + [ -e "$sh" ] && . "$sh" +done +unset -v sh diff --git a/bash/bashrc.d/bc.bash b/sh/shrc.d/bc.sh index 643678ac..643678ac 100644 --- a/bash/bashrc.d/bc.bash +++ b/sh/shrc.d/bc.sh diff --git a/sh/shrc.d/cd.sh b/sh/shrc.d/cd.sh new file mode 100644 index 00000000..dd98a422 --- /dev/null +++ b/sh/shrc.d/cd.sh @@ -0,0 +1,72 @@ +# If given two arguments, replace the first instance of the first argument with +# the second argument in $PWD, and make that the target of cd(). This POSIX +# version cannot handle options, but it can handle an option terminator (--), +# so e.g. `cd -- -foo -bar` should work. +cd() { + + # First check to see if we can perform the substitution at all + if ( + + # If we have any options, we can't do it, because POSIX shell doesn't + # let us (cleanly) save the list of options for use later in the script + for arg ; do + case $arg in + --) break ;; + -*) return 1 ;; + esac + done + + # Shift off -- if it's the first argument + [ "$1" = -- ] && shift + + # Check we have two non-null arguments + [ "$#" -eq 2 ] || return + [ -n "$1" ] || return + [ -n "$2" ] || return + + ) ; then + + # Set the positional parameters to an option terminator and what will + # hopefully end up being the substituted directory name + set -- -- "$( + + # If the first of the existing positional arguments is --, shift it + # off + [ "$1" = -- ] && shift + + # Current path: e.g. /foo/ayy/bar/ayy + cur=$PWD + # Pattern to replace: e.g. ayy + pat=$1 + # Text with which to replace pattern: e.g. lmao + rep=$2 + + # /foo/ + curtc=${cur%%"$pat"*} + # /bar/ayy + curlc=${cur#*"$pat"} + # /foo/lmao/bar/ayy + new=${curtc}${rep}${curlc} + + # Check pattern was actually in $PWD; this indirectly checks that + # $PWD and $pat are both actually set, too; it's valid for $rep to + # be empty, though + [ "$cur" != "$curtc" ] || exit + + # Check we ended up with something to change into + [ -n "$new" ] || exit + + # Print the replaced result + printf '%s\n' "$new" + )" + + # Check we have a second argument + if [ -z "$2" ] ; then + printf >&2 'cd(): Substitution failed\n' + return 1 + fi + fi + + # Execute the cd command as normal + command cd "$@" +} diff --git a/bash/bashrc.d/diff.bash b/sh/shrc.d/diff.sh index 2c752c8d..2c752c8d 100644 --- a/bash/bashrc.d/diff.bash +++ b/sh/shrc.d/diff.sh diff --git a/bash/bashrc.d/ed.bash b/sh/shrc.d/ed.sh index b87894df..4638d2cb 100644 --- a/bash/bashrc.d/ed.bash +++ b/sh/shrc.d/ed.sh @@ -5,7 +5,7 @@ ed() { # We're only adding options if input is from a terminal - if [[ -t 0 ]] ; then + if [ -t 0 ] ; then # Colon prompt (POSIX) set -- -p : "$@" @@ -18,7 +18,7 @@ ed() { # Execute the ed(1) call, in a wrapper if appropriate and with the # concluded options - if [[ -t 0 ]] && hash rlwrap 2>/dev/null ; then + if [ -t 0 ] && command -v rlwrap >/dev/null 2>&1 ; then command rlwrap ed "$@" else command ed "$@" diff --git a/sh/shrc.d/env.sh b/sh/shrc.d/env.sh new file mode 100644 index 00000000..4fa980f2 --- /dev/null +++ b/sh/shrc.d/env.sh @@ -0,0 +1,8 @@ +# Sort the output of env(1) for me +env() { + if [ "$#" -eq 0 ] ; then + command env | sort + else + command env "$@" + fi +} diff --git a/bash/bashrc.d/gdb.bash b/sh/shrc.d/gdb.sh index ec9d4137..ec9d4137 100644 --- a/bash/bashrc.d/gdb.bash +++ b/sh/shrc.d/gdb.sh diff --git a/bash/bashrc.d/gpg.bash b/sh/shrc.d/gpg.sh index 62d123ea..62d123ea 100644 --- a/bash/bashrc.d/gpg.bash +++ b/sh/shrc.d/gpg.sh diff --git a/sh/shrc.d/grep.sh b/sh/shrc.d/grep.sh new file mode 100644 index 00000000..df2101aa --- /dev/null +++ b/sh/shrc.d/grep.sh @@ -0,0 +1,35 @@ +# Our ~/.profile should already have made a directory with the supported +# options for us; if not, we won't be wrapping grep(1) with a function at all +[ -d "$HOME"/.cache/grep ] || return + +# Define function proper +grep() { + + # Add --color if the terminal has at least 8 colors + [ -e "$HOME"/.cache/grep/color ] && + [ "$({ tput colors || tput Co ; } 2>/dev/null)" -ge 8 ] && + set -- --color=auto "$@" + + # Add --binary-files=without-match to gracefully skip binary files + [ -e "$HOME"/.cache/grep/binary-files ] && + set -- --binary-files=without-match "$@" + + # Add --exclude to ignore .gitignore and .gitmodules files + [ -e "$HOME"/.cache/grep/exclude ] && + set -- \ + --exclude=.gitignore \ + --exclude=.gitmodules \ + "$@" + + # Add --exclude-dir to ignore version control dot-directories + [ -e "$HOME"/.cache/grep/exclude-dir ] && + set -- \ + --exclude-dir=.cvs \ + --exclude-dir=.git \ + --exclude-dir=.hg \ + --exclude-dir=.svn \ + "$@" + + # Run grep(1) with the concluded arguments + command grep "$@" +} diff --git a/bash/bashrc.d/hgrep.bash b/sh/shrc.d/hgrep.sh index 2f7f8d54..1c4c3ec5 100644 --- a/bash/bashrc.d/hgrep.bash +++ b/sh/shrc.d/hgrep.sh @@ -4,12 +4,12 @@ # $ history | grep PATTERN # hgrep() { - if ! (($#)) ; then - printf >&2 '%s: Need a pattern\n' "$FUNCNAME" + if [ "$#" -eq 0 ] ; then + printf >&2 'hgrep(): Need a pattern\n' exit 2 fi - if ! [[ -n $HISTFILE ]] ; then - printf >&2 '%s: No HISTFILE\n' "$FUNCNAME" + if ! [ -n "$HISTFILE" ] ; then + printf >&2 'hgrep(): No HISTFILE\n' exit 2 fi grep "$@" "$HISTFILE" diff --git a/sh/shrc.d/keychain.sh b/sh/shrc.d/keychain.sh new file mode 100644 index 00000000..82f83473 --- /dev/null +++ b/sh/shrc.d/keychain.sh @@ -0,0 +1,3 @@ +# If GPG_TTY is set, update it +[ -n "$GPG_TTY" ] || return +GPG_TTY=$(tty) diff --git a/sh/shrc.d/ksh.sh b/sh/shrc.d/ksh.sh new file mode 100644 index 00000000..b12f13c8 --- /dev/null +++ b/sh/shrc.d/ksh.sh @@ -0,0 +1,10 @@ +# If we're running some kind of ksh, we'll need to source its specific +# configuration if it was defined or if we can find it. Bash and Zsh invoke +# their own rc files first, which I've written to then look for ~/.shrc; ksh +# does it the other way around. +case $KSH_VERSION in + *'PD KSH '*|*'MIRBSD KSH '*) + [ -f "${KSH_ENV:-"$HOME"/.pdkshrc}" ] || return + . "${KSH_ENV:-"$HOME"/.pdkshrc}" + ;; +esac diff --git a/sh/shrc.d/ls.sh b/sh/shrc.d/ls.sh new file mode 100644 index 00000000..eec25eb7 --- /dev/null +++ b/sh/shrc.d/ls.sh @@ -0,0 +1,15 @@ +# Our ~/.profile should already have made a directory with the supported +# options for us; if not, we won't be wrapping ls(1) with a function at all +[ -d "$HOME"/.cache/ls ] || return + +# Define function proper +ls() { + + # Add --color if the terminal has at least 8 colors + [ -e "$HOME"/.cache/ls/color ] && + [ "$({ tput colors || tput Co ; } 2>/dev/null)" -ge 8 ] && + set -- --color=auto "$@" + + # Run ls(1) with the concluded arguments + command ls "$@" +} diff --git a/bash/bashrc.d/mkcd.bash b/sh/shrc.d/mkcd.sh index 6342d4a6..6342d4a6 100644 --- a/bash/bashrc.d/mkcd.bash +++ b/sh/shrc.d/mkcd.sh diff --git a/bash/bashrc.d/mysql.bash b/sh/shrc.d/mysql.sh index 0d5ddb86..d37c3ead 100644 --- a/bash/bashrc.d/mysql.bash +++ b/sh/shrc.d/mysql.sh @@ -11,11 +11,9 @@ # database=bar # mysql() { - local config - config=$HOME/.mysql/$1.cnf - if [[ -r $config ]] ; then + if [ -f "$HOME/.mysql/$1".cnf ] ; then shift - set -- --defaults-extra-file="$config" "$@" + set -- --defaults-extra-file="$HOME/.mysql/$1".cnf "$@" fi command mysql "$@" } diff --git a/bash/bashrc.d/pwgen.bash b/sh/shrc.d/pwgen.sh index 7ba056e5..7ba056e5 100644 --- a/bash/bashrc.d/pwgen.bash +++ b/sh/shrc.d/pwgen.sh diff --git a/bash/bashrc.d/rcsdiff.bash b/sh/shrc.d/rcsdiff.sh index 18b1d324..18b1d324 100644 --- a/bash/bashrc.d/rcsdiff.bash +++ b/sh/shrc.d/rcsdiff.sh diff --git a/sh/shrc.d/scp.sh b/sh/shrc.d/scp.sh new file mode 100644 index 00000000..cc46b229 --- /dev/null +++ b/sh/shrc.d/scp.sh @@ -0,0 +1,14 @@ +# Wrap scp(1) to check for missing colons +scp() { + # shellcheck disable=SC2048 + if [ "$#" -ge 2 ] ; then + case $* in + *:*) ;; + *) + printf >&2 'scp(): Missing colon, probably an error\n' + return 2 + ;; + esac + fi + command scp "$@" +} diff --git a/pdksh/pdkshrc.d/scr.pdksh b/sh/shrc.d/scr.sh index 01bd20cb..255b9322 100644 --- a/pdksh/pdkshrc.d/scr.pdksh +++ b/sh/shrc.d/scr.sh @@ -2,10 +2,5 @@ # files into $HOME, and making the system do cleanup for me. Single optional # argument is the string to use for naming the directory; defaults to "scr". scr() { - if (($# <= 1)) ; then - cd -- "$(mktd "${1:-scr}")" - else - printf 'ksh: scr: too many arguments\n' >&2 - return 2 - fi + cd -- "$(mktd "${1:-scr}")" } diff --git a/bash/bashrc.d/sudo.bash b/sh/shrc.d/sudo.sh index d6d91d12..a5883168 100644 --- a/bash/bashrc.d/sudo.bash +++ b/sh/shrc.d/sudo.sh @@ -1,7 +1,5 @@ # Add the -H parameter to sudo(8) calls, always use the target user's $HOME sudo() { - if [[ $1 != -v ]] ; then - set -- -H "$@" - fi + [ "$1" != -v ] && set -- -H "$@" command sudo "$@" } diff --git a/bash/bashrc.d/tmux.bash b/sh/shrc.d/tmux.sh index f0d0e36a..bd954be8 100644 --- a/bash/bashrc.d/tmux.bash +++ b/sh/shrc.d/tmux.sh @@ -2,7 +2,7 @@ tmux() { # If given any arguments, just use them as they are - if (($#)) ; then + if [ "$#" -gt 0 ] ; then : # If a session exists, just attach to it diff --git a/pdksh/pdkshrc.d/vim.pdksh b/sh/shrc.d/vim.sh index 37fc1871..e9174082 100644 --- a/pdksh/pdkshrc.d/vim.pdksh +++ b/sh/shrc.d/vim.sh @@ -1,7 +1,5 @@ # If Vim exists on the system, use it instead of ex, vi, and view -if ! hash vim 2>/dev/null ; then - return -fi +command -v vim >/dev/null 2>&1 || return # Define functions proper ex() { diff --git a/vim/bundle/abolish b/vim/bundle/abolish -Subproject e6a170cda8ee542ec5f1384c9643d4330ee6b18 +Subproject 125908e01dd69294743c7e22d3028855158aa44 diff --git a/vim/bundle/targets b/vim/bundle/targets -Subproject 5c2ae9dbe358b2b78bd887e09ff8d10294b2b23 +Subproject 81dd6d1c3c36622f8df6ee7c67ec3707838df75 @@ -69,7 +69,7 @@ if has('syntax') " Use my custom color scheme if possible, otherwise I'm happy with whatever " the default is, and it usually cares about my background set background=dark - silent! colorscheme juvenile + silent! colorscheme sahara endif " Command-line based features diff --git a/zsh/zprofile b/zsh/zprofile index b61ca248..95214ef6 100644 --- a/zsh/zprofile +++ b/zsh/zprofile @@ -1 +1,5 @@ -exec bash -l +# Zsh doesn't source ~/.profile by default, even when this file is absent. +# <https://sanctum.geek.nz/images/identifying-heresy.jpg> +if [[ -e $HOME/.profile ]] ; then + source "$HOME"/.profile +fi @@ -1 +1,11 @@ -exec bash +# Emacs keybindings even if EDITOR is vi(1) +bindkey -e + +# History settings +setopt histignorealldups sharehistory +HISTFILE=$HOME/.zsh_history +SAVEHIST=$((1 << 12)) +HISTSIZE=$((1 << 10)) + +# Load POSIX shell functions +source "$ENV" |