diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2016-12-13 13:03:49 +1300 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2016-12-13 13:03:49 +1300 |
commit | 6b5073d7c37a77e7afa2ddc48510e5ae0b09ac5f (patch) | |
tree | 502d41ffad32b30efdd76a7d470406e1db32b3a4 | |
parent | Add strik(6df) (diff) | |
download | dotfiles-6b5073d7c37a77e7afa2ddc48510e5ae0b09ac5f.tar.gz dotfiles-6b5073d7c37a77e7afa2ddc48510e5ae0b09ac5f.zip |
Add ad()
-rw-r--r-- | README.markdown | 3 | ||||
-rw-r--r-- | sh/shrc.d/ad.sh | 77 |
2 files changed, 80 insertions, 0 deletions
diff --git a/README.markdown b/README.markdown index 2e3b3e1f..f4c73817 100644 --- a/README.markdown +++ b/README.markdown @@ -167,6 +167,9 @@ terminals. 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: +* `ad()` is a `cd` shortcut accepting targets like `/u/l/b` for + `/usr/local/bin`, as long as they are unique, emulating a feature of the + Zsh `cd` builtin that I like. * `bc()` silences startup messages from GNU `bc(1)`. * `bd()` changes into a named ancestor of the current directory. * `diff()` forces the unified format for `diff(1)`. diff --git a/sh/shrc.d/ad.sh b/sh/shrc.d/ad.sh new file mode 100644 index 00000000..d3e5a90a --- /dev/null +++ b/sh/shrc.d/ad.sh @@ -0,0 +1,77 @@ +# Find an abbreviated path +ad() { + + # Check argument count + if [ "$#" -ne 1 ] ; then + printf >&2 'ad(): Need just one argument\n' + return 2 + fi + + # Change the positional parameters from the abbreviated request + # to any matched directory + set -- "$( + + # Clean up and anchor the request + req=${1%/}/ + case $req in + (/*) ;; + (*) req=${PWD%/}/${req#/}/ ;; + esac + + # Start building the target directory; go through the request piece by + # piece until it is used up + dir= + while [ -n "$req" ] ; do + + # Chop the next front bit off the request and add it to the dir + dir=${dir%/}/${req%%/*} + req=${req#*/} + + # If that exists, all is well and we can keep iterating + [ -d "$dir" ] && continue + + # Set the positional parameters to a glob expansion of the + # abbreviated directory given + set -- "$dir"* + + # Iterate through the positional parameters filtering out + # directories; we need to run right through the whole list to check + # that we have at most one match + entd= + for ent ; do + [ -d "$ent" ] || continue + + # If we already found a match and have found another one, bail + # out + if [ -n "$entd" ] ; then + printf >&2 'ad(): More than one matching dir for %s*:\n' \ + "$dir" + printf >&2 '%s\n' "$@" + exit 1 + fi + + # Otherwise, this can be our first one + entd=$ent + done + + # If we found no match, bail out + if [ -z "$entd" ] ; then + printf >&2 'ad(): No matching dirs: %s*\n' "$dir" + exit 1 + fi + + # All is well, tack on what we have found and keep going + dir=$entd + + done + + # Print the target + printf '%s\n' "$dir" + )" + + # If the subshell printed nothing, return with failure + [ -n "$1" ] || return + + # Try to change into the determined directory + command cd -- "$@" +} |