aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2016-08-20 12:08:31 +1200
committerTom Ryder <tom@sanctum.geek.nz>2016-08-20 12:09:36 +1200
commit304f4afceef0d421f2bba1ab9acff98fc83b000d (patch)
tree129ecdcae789e82a609ab0c76667d4ced768b1fe
parentRemove OLDPWD hack (diff)
downloaddotfiles-304f4afceef0d421f2bba1ab9acff98fc83b000d.tar.gz
dotfiles-304f4afceef0d421f2bba1ab9acff98fc83b000d.zip
Port bd() to POSIX sh
-rw-r--r--bash/bashrc.d/bd.bash78
-rw-r--r--sh/shrc.d/bd.sh67
2 files changed, 67 insertions, 78 deletions
diff --git a/bash/bashrc.d/bd.bash b/bash/bashrc.d/bd.bash
deleted file mode 100644
index 23a2d380..00000000
--- a/bash/bashrc.d/bd.bash
+++ /dev/null
@@ -1,78 +0,0 @@
-# Move back up the directory tree to the first directory matching the name
-bd() {
-
- # For completeness' sake, we'll pass any options to cd
- local arg
- local -a opts
- for arg ; do
- case $arg in
- --)
- shift
- break
- ;;
- -*)
- shift
- opts[${#opts[@]}]=$arg
- ;;
- *)
- break
- ;;
- esac
- done
-
- # We should have zero or one arguments after all that, bail if there are
- # more
- if (($# > 1)) ; then
- printf 'bash: %s: usage: %s [PATH]\n' \
- "$FUNCNAME" "$FUNCNAME" >&2
- return 2
- fi
-
- # The requested pattern is the first argument; strip trailing slashes if
- # there are any
- local req=$1
- [[ $req != / ]] || req=${req%/}
-
- # What to do now depends on the request
- local dirname
- case $req in
-
- # If no argument at all, just go up one level
- '')
- dirname=..
- ;;
-
- # Just go straight to the root or dot directories if asked
- /|.|..)
- dirname=$req
- ;;
-
- # Anything else with a leading / needs to anchor to the start of the
- # path
- /*)
- dirname=$req
- if [[ $PWD != "$dirname"/* ]] ; then
- printf 'bash: %s: Directory name not in path\n' \
- "$FUNCNAME" >&2
- return 1
- fi
- ;;
-
- # In all other cases, iterate through the directory tree to find a
- # match, or whittle the dirname down to an empty string trying
- *)
- dirname=${PWD%/*}
- while [[ -n $dirname && $dirname != */"$req" ]] ; do
- dirname=${dirname%/*}
- done
- if [[ -z $dirname ]] ; then
- printf 'bash: %s: Directory name not in path\n' \
- "$FUNCNAME" >&2
- return 1
- fi
- ;;
- esac
-
- # Try to change into the determined directory
- builtin cd "${opts[@]}" -- "$dirname"
-}
diff --git a/sh/shrc.d/bd.sh b/sh/shrc.d/bd.sh
new file mode 100644
index 00000000..0d1abbcf
--- /dev/null
+++ b/sh/shrc.d/bd.sh
@@ -0,0 +1,67 @@
+# Move back up the directory tree to the first directory matching the name
+bd() {
+
+ # Set positional parameters to an option terminator and what will hopefully
+ # end up being a target directory
+ set -- -- "$(
+
+ # If the first of the existing positional arguments is --, shift it
+ # off
+ [ "$1" = -- ] && shift
+
+ # There's no more than one argument after that
+ [ "$#" -le 1 ] || exit 1
+
+ # The requested pattern is the first argument, defaulting to just the
+ # parent directory
+ req=${1:-..}
+
+ # Strip trailing slashes if a trailing slash isn't 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='' ;;
+ 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
+ printf '%s\n' "$dirname"
+
+ # If the subshell failed, return from the function with the same exit value
+ )" || return
+
+ # Try to change into the determined directory
+ command cd "$@"
+}