5

Assume someuser has a home directory /home/someuser

NAME=someuser

In bash - what expression to I use combining tilde (~) and $NAME to return the users home directory?

HOMEDIRECTORY=~someuser
echo $HOMEDIRECTORY
/home/someuser
NAME=someuser
echo ~$NAME
~someuser

any suggestions?

Dennis Williamson
  • 303,596
  • 86
  • 357
  • 418
iaroot
  • 51
  • 1
  • 2

6 Answers6

16

Safer:

eval HOMEDIRECTORY="$(printf "~%q" "$NAME")"

Here the %q option to printf quotes and escapes dangerous characters.

If $NAME is joe, you'd get something like /home/joe. For root, you might get /root. For "abc;rm something" you'd get "~abc;rm something" instead of having something removed.

Dennis Williamson
  • 303,596
  • 86
  • 357
  • 418
  • +1 for solution. Also, minor typo: should not have trailing grave accent. Should be eval HOMEDIRECTORY="$(printf "~%q" "$NAME")" – Larry K Jan 27 '10 at 18:45
  • I like this solution because it overcomes problems with `eval` and is neat, clean, easy to read, and easy to debug. Thanks. – Felipe Alvarez Oct 28 '16 at 04:09
6

If you have access to getent:

getent passwd "$NAME" | cut -d: -f 6
Ignacio Vazquez-Abrams
  • 699,552
  • 132
  • 1,235
  • 1,283
1

Tilde ( ~ ) it's the same as $HOME so, not all the user will have as root to home the same directory.

But if you insist in using the tilde this do the work:

echo ~/../$NAME

See:

$ pwd
/home/oreyes
$ export NAME=john 
$ export DIRECTORYNAME=~/../$NAME
$ cd $DIRECTORYNAME
$ pwd
/home/john
OscarRyz
  • 184,433
  • 106
  • 369
  • 548
  • 1
    This assumes that all users' home directories, including the current one, are siblings. This will fail especially spectacularly if the current user is `root`. – Ignacio Vazquez-Abrams Jan 15 '10 at 04:35
  • No guarantees even when not root. For example, homes on CMU's Andrew are given out following the pattern `/afs/andrew.cmu.edu/usr##/$LOGNAME`, where `##` is a semi-random integer. – ephemient Jan 15 '10 at 05:26
  • I like this simple solution since I know i will run this case without root, good enough. – Larry Cai Jan 16 '13 at 14:01
1

Interesting difference between bash and csh, where ~$VARNAME actually does what you'd expect!

This is ugly, but it seems to work in bash:

homedir=`eval "echo ~$USERNAME"`

Now $homedir holds the home directory associated with $USERNAME.

Jim Lewis
  • 39,858
  • 6
  • 80
  • 93
  • That is indeed the way to do it in bash. Tilde expansion happens before parameter expansion, so the shell actually tries to expand ~$USERNAME into the home directory of a user whose name is literally $USERNAME, and not the contents of $USERNAME. – Wilson Jan 15 '10 at 05:36
  • 2
    Just make sure `$USERNAME` is sanitized first and doesn't contain stuff like `; sudo rm -rf /`, 'kay? – ephemient Jan 15 '10 at 05:51
  • 1
    @ephemient: Good advice! I'm surprised "little Bobby Tables" hasn't shown up yet! – Jim Lewis Jan 15 '10 at 07:39
1

BEST METHOD

Required: nothing (n.b., this is the same technique as getent without requiring getent)

home() { # returns empty string on invalid user
    grep "^$1:" /etc/passwd | cut -d ':' -f 6
}

# grep "^$user:" /etc/passwd | cut -d ':' -f 6
/var/lib/memcached

NICE METHOD FOR ROOT LINUX

Required: Linux, root (or sudo)

home() { # returns errorlevel 1 on invalid user
    su "$1" -s '/bin/sh' -c 'echo $HOME'
} 

# su memcached -s '/bin/sh' -c 'echo $HOME'
/var/lib/memcached

SOLUTION FOR COMPLETE EXPANSION

magic() { # returns unexpanded tilde express on invalid user
    local _safe_path; printf -v _safe_path "%q" "$1"
    eval "ln -sf $_safe_path /tmp/realpath.$$"
    readlink /tmp/realpath.$$
    rm -f /tmp/realpath.$$
}

Example usage:

$ magic ~nobody/would/look/here
/var/empty/would/look/here

$ magic ~invalid/this/will/not/expand
~invalid/this/will/not/expand

METHOD FOR HARNESSING CSH

This is a BASH script, it just calls csh.

Required: csh

home() { # return errorlevel 1 on invalid user
    export user=$1; csh -c "echo ~$user"
}

$ export user=root; csh -c "echo ~$user"
/var/root

$ export user=nodfsv; csh -c "echo ~$user"
Unknown user: nodfsv.

METHOD OF DESPERATION

Required: finger (deprecated)

home() {
    finger -m "$1" | 
    grep "^Directory:" | 
    sed -e 's/^Directory: //' -e 's/ .*//'
}

# finger -m "haldaemon" | 
> grep "^Directory:" | 
> sed -e 's/^Directory: //' -e 's/ .*//'
/home/haldaemon

You can combined the grep operation into sed, but since this method is sucky, I wouldn't bother.

Orwellophile
  • 11,307
  • 3
  • 59
  • 38
0

one alternative way

awk -F":" '{print "user: "$1", Home directory is: "$6}' /etc/passwd
ghostdog74
  • 286,686
  • 52
  • 238
  • 332