aboutsummaryrefslogtreecommitdiff
path: root/sh
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2017-05-25 18:21:23 +1200
committerTom Ryder <tom@sanctum.geek.nz>2017-05-25 18:21:42 +1200
commitb4b144c3f8aa98a26b9a59c204ec0d5b4619ef72 (patch)
treed18fa49fc68a8ce79aef6055e1a8ebc49c44859b /sh
parent3f9a35e5babdc63d32408851296d235fa632834b (diff)
downloaddotfiles-b4b144c3f8aa98a26b9a59c204ec0d5b4619ef72.tar.gz
Shorter/saner implementation for bd()
Avoids subshell mess and consequent trailing-space workaround
Diffstat (limited to 'sh')
-rw-r--r--sh/shrc.d/bd.sh85
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"
}