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/bashdoExpand() {  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:Did I miss any cases or get any cases wrong? (Tests in the github repo.)Can this be improved in any meaningful ways?
Expanding tilde inside assignments and strings in bash
bash;shell
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