From 9ed69d70d9201817c7f36c7f210ce163e84eb54b Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Fri, 26 May 2017 00:39:02 +1200 Subject: Reimplement sd() without subshell --- sh/shrc.d/bd.sh | 6 ++--- sh/shrc.d/sd.sh | 80 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 44 insertions(+), 42 deletions(-) (limited to 'sh') diff --git a/sh/shrc.d/bd.sh b/sh/shrc.d/bd.sh index 5b2c3d59..2dc21173 100644 --- a/sh/shrc.d/bd.sh +++ b/sh/shrc.d/bd.sh @@ -7,8 +7,8 @@ bd() { return 2 fi - # Look at argument given - case $1 in + # Look at argument given; default to going up one level + case ${1:-..} in # If it has a leading slash or is . or .., don't touch the arguments /*|.|..) ;; @@ -18,7 +18,7 @@ bd() { *) # Push the current directory onto the stack - set -- "$1" "$PWD" + set -- "${1%/}" "$PWD" # Keep chopping at the current directory until it's empty or it # matches the request diff --git a/sh/shrc.d/sd.sh b/sh/shrc.d/sd.sh index 4d63b7d6..561a77f4 100644 --- a/sh/shrc.d/sd.sh +++ b/sh/shrc.d/sd.sh @@ -40,48 +40,50 @@ sd() { return 2 fi - # Change positional parameters to what will hopefully be a completed - # substitution - set -- "$( + # Read sole optional argument + case $1 in - # Set the positional parameters to either the requested directory, or - # all siblings of the current directory if no request - spec=$1 - set -- - if [ -n "$spec" ] ; then - set -- "$@" ../"$spec" - else - for sib in ../.* ../* ; do - case ${sib#../} in - (.|..|"${PWD##*/}") continue ;; - esac - set -- "$@" "$sib" - done - fi + # If blank, get a full list of directories at this level; include + # dotfiles, but not the . and .. entries, using glob tricks to avoid + # Bash ruining things with `dotglob` + '') + set -- ../[!.]*/ + [ -e "$1" ] || shift + set -- ../.[!.]*/ "$@" + [ -e "$1" ] || shift + set -- ../..?*/ "$@" + [ -e "$1" ] || shift + ;; - # We should have exactly one sibling - case $# in - (1) ;; - (0) - printf >&2 'sd(): No siblings\n' - exit 1 - ;; - (*) - printf >&2 'sd(): More than one sibling\n' - exit 1 - ;; - esac + # If not, get that directory, and the current one; shift it off if it + # doesn't exist + *) + set -- ../"${1%/}"/ ../"${PWD##*/}"/ + [ -e "$1" ] || shift + ;; + esac - # Print the target with trailing slash to work around newline stripping - printf '%s/' "${1%/}" - )" + # We should now have two parameters: the current directory and the matched + # sibling + case $# in + 2) ;; + 0|1) + printf >&2 'sd(): No match\n' + return 1 + ;; + *) + printf >&2 'sd(): Multiple matches\n' + return 1 + ;; + esac - # Remove trailing slash - set -- "${1%/}" + # Find which of these two is not the current directory and set that as our + # sole parameter + case $1 in + ../"${PWD##*/}"/) set -- "$2" ;; + *) set -- "$1" ;; + esac - # If the subshell printed nothing, return with failure - [ -n "$1" ] || return - - # Try to change into the determined directory - command cd -- "$@" + # Try and change into the first parameter + command cd -- "$1" } -- cgit v1.2.3