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:
Did I miss any cases or get any cases wrong? (Tests in the github repo.)
Can this be improved in any meaningful ways?
1 Answer 1
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
-
\$\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 intoDIRSTACK
). Fixing the others is escaping me at the moment. Also indexing intoDIRSTACK
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\$Etan Reisner– Etan Reisner2015年12月14日 04:50:52 +00:00Commented 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\$mikeserv– mikeserv2015年12月14日 05:24:20 +00:00Commented 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 elseunset
altogether. that would make sense, but what else should happen? \$\endgroup\$mikeserv– mikeserv2015年12月14日 20:20:34 +00:00Commented 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\$Etan Reisner– Etan Reisner2015年12月16日 13:14:28 +00:00Commented 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\$Etan Reisner– Etan Reisner2015年12月16日 13:14:47 +00:00Commented Dec 16, 2015 at 13:14