You are right. Then maybe do it like this:
Code:
IFS=';&|()`'
read -ep '> ' path junk
path=$(eval echo $path)
echo $path
I see why this is suboptimal and rather fragile as it would break on paths containing characters listed in $IFS, but at least the full semantics of ~ would be preserved.
Update.
After giving it some more thought, now I guess the most prudent way would be using the case statement:
Code:
#!/bin/sh
LC_ALL=C # for [a-z] to work as expected
test -n "$1" && path=$1 || read -p '> ' path
case $path in ~*)
pfx=${path%%/*}; tag=${pfx#\~}; tail=${path#$pfx}
case $tag in
'') path=$HOME$tail;;
+) path=$PWD$tail;;
-) test -n "$OLDPWD" && path=$OLDPWD$tail;;
[a-z_]*) passwd=`getent passwd "$tag"` && pfx=${passwd%:*}&&path=${pfx##*:}$tail;;
# Some custom shortcuts
DC) path=$HOME/Documents$tail;;
DL) path=$HOME/Downloads$tail;;
DT) path=$HOME/Desktop$tail;;
ML) path=$HOME/Mail$tail;;
MU) path=$HOME/Music$tail;;
PC) path=$HOME/Pictures$tail;;
PB) path=$HOME/Public$tail;;
TL) path=$HOME/Templates$tail;;
VD) path=$HOME/Videos$tail;;
CF) path=$HOME/.config$tail;;
LC) path=$HOME/.local/share$tail;;
MD) path=/media$tail;;
esac
esac
echo $path
The same in bash
Code:
#!/bin/bash
LC_ALL=C # for [a-z] to work as expected
shopt -s extglob # for $DIRSTACK
declare -A shortcuts
shortcuts=(
[DC]=Documents [DL]=Downloads [DT]=Desktop [ML]=Mail [MU]=Music
[PC]=Pictures [PB]=Public [TL]=Templates [VD]=Videos [CF]=.config
[LC]=.local/share
)
[[ -n $1 ]] path=$1 || read -ep '> ' path
if [[ $path == ~* ]]; then
pfx=${path%%/*}; tag=${pfx:1}; tail=${path#$pfx}
case $tag in
'') path=$HOME$tail;;
+) path=$PWD$tail;;
-) [[ -n $OLDPWD ]] && path=$OLDPWD$tail;;
?(+|-)+([0-9])) path=${DIRSTACK[$tag]}$tail;;
DC|DL|DT|MU|PC|PB|TL|VD|CF|LC) path=$HOME/${shortcuts[$tag]}$tail};;
MD) path=/media$tail;;
[a-z_]*) ifs=$IFS;IFS=:; passwd=(`getent passwd "$tag"`)&&path=${passwd[5]}$tail; IFS=$ifs;;
esac
fi
echo $path
Bookmarks