3

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

8
  • For reference: wiki.bash-hackers.org/syntax/expansion/tilde Commented Nov 30, 2018 at 21:02
  • The output looks "fine" ~xyz123 but it is not the path to xyz123 home directory. Commented Nov 30, 2018 at 21:05
  • 2
    None of the possible workarounds are very attractive. Muttering terms of abuse such as eval won't endear me to the security folks — and there's no blame to them for that. Commented Nov 30, 2018 at 21:09
  • 1
    Taking a step way back, I'd say it's rare to need someone else's home directory, which isn't necessarily accessible by someone else anyway. Either the script will be run by omar, in which case you'll just use ~, or the script will be run as root, who can just use su to become omar as necessary. Commented Nov 30, 2018 at 21:13
  • 1
    You might want to use the cdable_vars option instead; add a variable like omarhome=/home/omar (look it up manually once and store the value in the variable), then cd omarhome will be equivalent to cd "$omarhome". (Other commands, of course, will have to use the variable more explicitly, e.g. ls "$omarhome".) Commented Nov 30, 2018 at 21:23

2 Answers 2

3

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)" 
Sign up to request clarification or add additional context in comments.

1 Comment

eg home() { getent passwd ${1:?Missing user name} | cut -f6 -d:; } followed by -- eg ls "$(home $omar)". Not as convenient as ~ certainly, but safest.
0

I would go with checking if "$omar" is a valid user with id and then using eval to force double expansion. So protect against evil eval and then do it.

if ! id "$omar" >/dev/null 2>&1; echo "Error: user with the name $omar does not exist!" >&2 exit 1 fi eval echo "\"~$omar\"" 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.