diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2017-05-25 18:21:23 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2017-05-25 18:21:42 +1200 |
commit | b4b144c3f8aa98a26b9a59c204ec0d5b4619ef72 (patch) | |
tree | d18fa49fc68a8ce79aef6055e1a8ebc49c44859b /sh/shrc.d | |
parent | Update submodules (diff) | |
download | dotfiles-b4b144c3f8aa98a26b9a59c204ec0d5b4619ef72.tar.gz dotfiles-b4b144c3f8aa98a26b9a59c204ec0d5b4619ef72.zip |
Shorter/saner implementation for bd()
Avoids subshell mess and consequent trailing-space workaround
Diffstat (limited to 'sh/shrc.d')
-rw-r--r-- | sh/shrc.d/bd.sh | 85 |
1 files changed, 29 insertions, 56 deletions
diff --git a/sh/shrc.d/bd.sh b/sh/shrc.d/bd.sh index bf64a9aa..02da6773 100644 --- a/sh/shrc.d/bd.sh +++ b/sh/shrc.d/bd.sh @@ -3,68 +3,41 @@ bd() { # Check argument count if [ "$#" -gt 1 ] ; then - printf >&2 'bd(): Too many arguments' + printf >&2 'bd(): Too many arguments\n' return 2 fi - # Set positional parameters to an option terminator and what will hopefully - # end up being a target directory - set -- "$( + # Look at argument given + case $1 in - # The requested pattern is the first argument, defaulting to just the - # parent directory - req=${1:-..} + # If it has a leading slash or is . or .., don't touch the arguments + /*|.|..) ;; - # Strip trailing slashes if a trailing slash is not the whole pattern - [ "$req" = / ] || req=${req%/} + # Otherwise, we'll try to find a matching ancestor and then shift the + # initial request off the argument list + *) - # What to do now depends on the request - case $req in + # Push the current directory onto the stack + set -- "$1" "$PWD" - # Just go straight to the root or dot directories if asked - (/|.|..) - dirname=$req - ;; - - # Anything with a leading / needs to anchor to the start of the - # path. A strange request though. Why not just use cd? - (/*) - dirname=$req - case $PWD in - ("$dirname"/*) ;; - (*) dirname='' ;; + # Keep chopping at the current directory until it's empty or it + # matches the request + while [ -n "$2" ] ; do + set -- "$1" "${2%/*}" + case $2 in + (*/"$1") break ;; esac - ;; - - # In all other cases, iterate through the PWD to find a match, or - # whittle the target down to an empty string trying - (*) - dirname=$PWD - while [ -n "$dirname" ] ; do - dirname=${dirname%/*} - case $dirname in - (*/"$req") break ;; - esac - done - ;; - esac - - # Check we have a target after all that - if [ -z "$dirname" ] ; then - printf >&2 'bd(): Directory name not in path\n' - exit 1 - fi - - # Print the target with trailing slash to work around newline stripping - printf '%s/' "${dirname%/}" - )" - - # Remove trailing slash - set -- "${1%/}" - - # If the subshell printed nothing, return with failure - [ -n "$1" ] || return - - # Try to change into the determined directory - command cd -- "$@" + done + + # If the first argument ended up empty, we have no match + if [ -z "$2" ] ; then + printf >&2 'bd(): No match\n' + return 1 + fi + shift + ;; + esac + + # We have a match; try and change into it + command cd -- "$1" } |