Search code examples
bashshellvariable-expansiontilde-expansion

Expand variable before tilde


I'm sure this has been asked before but I can't find anything. We have inscrutable login names on a shared machine and want to use shell variables to substitute the hard-to-remember login names for people's real names.

For example, let's say Omar's login name is xyz123. I can do this:

$ omar=xyz123
$ echo ~$omar

and output looks fine:

~xyz123

but if I type this:

$ ls ~$omar

there is an error:

ls: cannot access ~xyz123: No such file or directory

I think it's because tilde expansion happens before variable expansion but can't figure out how to get around this.

Perhaps this answer is related although I'm not sure: How to manually expand a special variable (ex: ~ tilde) in bash


Solution

  • bash expands the tilde before the variable. See https://www.gnu.org/software/bash/manual/bash.html#Shell-Expansions

    The shell will see if the literal characters $ o m a r are a login name. As they are not, the tilde is not expanded. The shell eventually sees $omar as a variable and substitutes that. It then hands the expanded word ~xyz123 to echo which just prints it.

    Similarly, it hands the word ~xyz123 to ls. Since ls does not do its own tilde expansion, it is looking for a file in your current directory named ~xyz123 with a literal tilde. Since such a file does not exist you get that error.

    If you want ls ~$var to list files, you need eval ls ~$var. Or, since eval is considered very unsafe to use casually, you could do this instead:

    ls "$(getent passwd "$omar" | cut -d: -f6)"