On Thu, Apr 04, 2013 at 09:17:00PM +0800, Chris Down wrote: > Perhaps my reply here[1] can help out. Only looked briefly, but it seems it > could at least eliminate the calls to eval (although it doesn't support some > more rare tilde expansions). > > Chris > > 1: http://lists.gnu.org/archive/html/help-bash/2013-02/msg00030.html
That code reads /etc/passwd directly. That will fail on systems where user accounts are provided by NIS, NIS+, LDAP, or any other thing that's not /etc/passwd. Here's the code that I wrote on another mailing list, from which parts of the discussion have already started being echoed here: case $1 in \~ ) printf '%s\n' "$HOME" ;; \~/* ) printf '%s\n' "$HOME/${1#??}" ;; \~* ) user=${1%%/*} path=${1#*/} # Sanitize user before feeding it to eval. # You must adjust this code based on what characters are legal in your # system's usernames. If your system allows shell metacharacters in # usernames, you are screwed. Just give up now (switch to perl). user=${user#\~} user2=${user//[^[:alnum:]._-]/} if [[ $user != "$user2" ]]; then echo "Error: invalid characters in username" >&2 exit 1 fi eval "home=~$user2" case $1 in */* ) printf '%s\n' "$home/$path" ;; * ) printf '%s\n' "$home" ;; esac ;; * ) printf '%s\n' "$1" ;; esac As I said on the other list, this code must be adjusted based on your local system's definition of what constitutes a valid username. Not all valid usernames can be accomodated by this approach -- particularly, user accounts with dollar signs in them are NOT going to be manageable without a second pass to escape those. If you need more flexibility than this provides, consider switching to some other language that has support for calling getpwnam() directly. (There was also some ambiguity in the stated goals in the request that appeared on the other mailing list. The code presented here was written under the interpretation that the input should be tilde-expanded in the same way that bash performs tilde expansions, and that it was safe to ignore tilde expansions in inputs of the form "hostname:~username/pathname" and "variable=~username/pathname".)