2
\$\begingroup\$

Inspired by the work Charles Duffy did in this answer and the work of Jonathan Leffler in this one and because I couldn't leave well-enough alone.

I went and wrote expandTilde.sh:

#!/bin/bash
doExpand() {
 local path
 local -a resultPathElements
 for path in "$@"; do
 : "$path"
 case $path in
 "~+")
 path=$PWD
 ;;
 "~+"/*)
 path=$PWD/${path#"~+/"}
 ;;
 "~-")
 path=$OLDPWD
 ;;
 "~-"/*)
 path=$OLDPWD/${path#"~-/"}
 ;;
 "~")
 path=${HOME-~}
 ;;
 "~"/*)
 path=$HOME/${path#"~/"}
 ;;
 "~"[0-9]|"~"[+-][0-9])
 local num=${path#"~"}
 local op=${num%%[0-9]*}
 num=${num#[+-]}
 local opath=$path
 if [ "$op" = "-" ]; then
 ((num+=1))
 fi
 path=${DIRSTACK[@]: $op$num:1}
 : "${path:=$opath}"
 ;;
 "~"*)
 local username=${path%%/*}
 username=${username#"~"}
 IFS=: read -r _ _ _ _ _ homedir _ < <(getent passwd "$username")
 if [ "$homedir" ]; then
 if [[ $path = */* ]]; then
 path=${homedir}/${path#*/}
 else
 path=$homedir
 fi
 fi
 ;;
 esac
 resultPathElements+=( "$path" )
 done
 local result
 printf -v result '%s:' "${resultPathElements[@]}"
 printf '%s\n' "${result%:}"
}
expandAssign() {
 local -a pathElements
 IFS=: read -r -a pathElements <<<"1ドル"
 : "${pathElements[@]}"
 doExpand "${pathElements[@]}"
}
expandString() {
 doExpand "1ドル"
}

So two questions:

  1. Did I miss any cases or get any cases wrong? (Tests in the github repo.)

  2. Can this be improved in any meaningful ways?

asked Nov 11, 2015 at 4:07
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

case is most useful when its order of expansion is considered. if you construct your conditions in such a way that a previous match will narrow the possibilities for the current match, then you can get much nearer much quicker to your target match. what's more, case seems always to make better sense as a function in itself - so that it might call itself recursively when matches are ambiguous. consider the following:

 pathcase()
 case 1ドル in ([!~]*|'') ! :;; ### ^tilde or else
 (*/*)
 pathcase "${1%%/*}" "${1#*/}" ### squeeze to relevant ele
 ;;
 (?)
 path=${HOME-~}${2+/2ドル} ### let expansions work, to
 ;;
 (?-)
 path=${OLDPWD:+$OLDPWD${2+/2ドル}} ### its not always set
 ;;
 (?+)
 path=$PWD${2+/2ドル} ### it should be
 ;;
 (?*[!-+0-9]*|??*[-+]*) ### negate
 pathchk -p -- "${1#?}" && ### requires standards comp
 eval '[ "1ドル" != '"1ドル ] && ### which makes this safe
 path=1ドル${2+/\2ドル}" ### and this
 ;;
 (${BASH_VERSION+$(( path =
 ${#DIRSTACK[@]}-${1#?+}-1))}|\
 ${BASH_VERSION+${path##-*}}*) ### matches !bash||bad inde
 unset path
 ${path?bad tilde: "1ドル${2+/2ドル}"} ### break w/ error
 ;;
 (?+*)
 path=${DIRSTACK[${1#?+}]}${2+/2ドル}
 ;;
 (*) path=${DIRSTACK[path]}${2+/2ドル}
 esac
answered Dec 12, 2015 at 21:32
\$\endgroup\$
7
  • \$\begingroup\$ Nice. This is certainly much shorter. The recursion is clever (though I don't know how much it really helps here). This doesn't quite work correctly though (it fails on the ~+ non-digit, the ~- digit cases and the ~+ digit out of bounds cases). Fixing the latter is easy (just check for that before indexing into DIRSTACK). Fixing the others is escaping me at the moment. Also indexing into DIRSTACK generates a warning that mine doesn't. I've made some changes to mine based on insights from this though. You can check the repo for them (the new version is only 25 lines for the case). \$\endgroup\$ Commented Dec 14, 2015 at 4:50
  • \$\begingroup\$ @EtanReisner - what's it supposed to do with a non-digit? the recursion matters - but it only ever happens the one time, of course. it makes it much easier to negate. I was able to use the dirstack thing. in truth, i almost never use bash - or arrays - and i'm admittedly not all that hip to the popdirs deals, but i checked and it worked for $PWD and $OLDPWD and a stack of 4 or 5 test dirs. \$\endgroup\$ Commented Dec 14, 2015 at 5:24
  • \$\begingroup\$ @EtanReisner - i guess i know what you mean now about the negatives failing now - apparently bash reports errors for unset array indexes only when they are referenced in reverse - with a the - negative index. so i fixed that by doing less and just ~ twiddling the negative indexes. but how do the positives fail? if a user references an unset index $path should be set null - or else unset altogether. that would make sense, but what else should happen? \$\endgroup\$ Commented Dec 14, 2015 at 20:20
  • \$\begingroup\$ Ah... I see what the recursion gains you now. Yeah, that is useful. I would probably have just handled that manually myself. This version still fails on a number of tests (and this shouldn't error on a bad tilde it should just return the original, which assigning in the case label, while clever, makes a bit hard without adding a temporary variable). I think I'll be accepting this answer though as it gave me many insights, a few new test cases and caused great improvements to the original. \$\endgroup\$ Commented Dec 16, 2015 at 13:14
  • \$\begingroup\$ I might file a new question with the current code to get more feedback though. (... Eventually at least given the pace at which I got answer to this question. =)) \$\endgroup\$ Commented Dec 16, 2015 at 13:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.