aboutsummaryrefslogtreecommitdiff
path: root/sh/shrc.d/bd.sh
diff options
context:
space:
mode:
Diffstat (limited to 'sh/shrc.d/bd.sh')
-rw-r--r--sh/shrc.d/bd.sh99
1 files changed, 38 insertions, 61 deletions
diff --git a/sh/shrc.d/bd.sh b/sh/shrc.d/bd.sh
index bf64a9aa..29bde513 100644
--- a/sh/shrc.d/bd.sh
+++ b/sh/shrc.d/bd.sh
@@ -1,70 +1,47 @@
# Move back up the directory tree to the first directory matching the name
bd() {
- # Check argument count
+ # Check arguments; default to ".."
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 -- "$(
-
- # The requested pattern is the first argument, defaulting to just the
- # parent directory
- req=${1:-..}
-
- # Strip trailing slashes if a trailing slash is not the whole pattern
- [ "$req" = / ] || req=${req%/}
-
- # What to do now depends on the request
- case $req in
-
- # 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='' ;;
+ set -- "${1:-..}"
+
+ # Look at argument given; default to going up one level
+ case $1 in
+
+ # If it's slash, dot, or dot-dot, we'll just go there, like `cd` would
+ /|.|..) ;;
+
+ # Anything else with a slash anywhere is an error
+ */*)
+ printf >&2 'bd(): Illegal slash\n'
+ return 2
+ ;;
+
+ # Otherwise, add and keep chopping at the current directory until it's
+ # empty or it matches the request, then shift the request off
+ *)
+ set -- "$1" "$PWD"
+ while : ; do
+ case $2 in
+ */"$1"|'') break ;;
+ */) set -- "$1" "${2%/}" ;;
+ */*) set -- "$1" "${2%/*}" ;;
+ *) set -- "$1" '' ;;
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
+ done
+ shift
+ ;;
+ esac
+
+ # If we have nothing to change into, there's an error
+ if [ -z "$1" ] ; then
+ printf >&2 'bd(): No match\n'
+ return 1
+ fi
- # Try to change into the determined directory
- command cd -- "$@"
+ # We have a match; try and change into it
+ command cd -- "$1"
}