Changing directories using variables.

I can't seem to solve this problem. :mad::mad: Please assist. Thanks!

#!/bin/bash

UserDir="$(echo ~$1)"

echo "Changing directory with variables"
cd "$UserDir"
echo "Changing directory without variables"
cd ~pearsn
pwd

Output:
pearsn$ sh -x ./test.bash pearsn
++ echo '~pearsn'
+ UserDir='~pearsn'
+ echo 'Changing directory with variables'
Changing directory with variables
+ cd '~pearsn'
./test.bash: line 6: cd: ~pearsn: No such file or directory
+ echo 'Changing directory without variables'
Changing directory without variables
+ cd /Users/pearsn
+ pwd
/Users/pearsn

cd ~$1

Same result. No luck. I've tried this as well

cd UserDir=$(echo ~$1)
cd UserDir=`echo ~$1`
cd UserDir="~$(echo $1)"

You cant put ~$1 together you need to add it like ~/$1

~ (tilde) will expand to user home directory(current user).

# echo '~'
~
# echo "~"
~
# echo ~
/usr/danmero

If you wrapping with quotes or double quote will prevent expansion.

The answer is to use "eval" but the reason is not easy to explain. I'll give it a try:

The shell evaluates commandlines on a fixed step-by-step basis. For instance you rely implicitly on this mechanism when you write "var=$(somecommand $othervar)" as you do in your script.

The shell has somehow to follow a recipe to expand "$othervar" prior to "$(...)", because the other way round the command would get a literal "$othervar" as an argument instead of the content of the variable.

For the same reason the following will not work:

var="something"
varname="var"
echo $$varname

We could expect the shell to first expand "$varname" to "var" and then expand "$var" to "something" - but this is not the case because all variables are expanded in the same step and therefore at the same time, not one after the other.

For the same reason your code fails: the step where "~" is expanded to the home directory is already over when you try to evaluate it and therefore you are left with a literal "~pearsn" instead of the home directory of the user.

Still, there is good news: you can restart the evaluation process with step 1 by using the keyword "eval" - in fact this is the reason for the existence of this keyword. Lets start with the variables example from above:

var="something"
varname="var"
eval echo \$$varname

The shell would - because finding nothing else making sense - the "$$" expand to the PID, which is why we will have to protect it with the backslash. So the first time the line is evaluated it goes like this:

(eval)=keyword (echo)=keyword (\$)=a "$" which is meant to remain one ($varname)=oops, we have to expand that one -> replace with "var"

Since the "eval" is there the resulting line is now evaluated again (without the "eval" now):

(echo)=keyword ($var)=oops, needs expanding -> "something"

And as you will notice this works in the expected way.

What does this mean to your problem? Try the following:

#!/bin/bash

UserDir="$(echo ~$1)"

echo "Changing directory with variables"
eval cd "$UserDir"

echo $PWD

I hope this helps.

bakunin

PS: Notice, that the evaluation process is slightly different in ksh and in bash. Your script would have worked in Korn shell, but fails in bash, because the steps are laid out a little differently.

1 Like

Thank you all for replying, especially bakunin for the thorough explanation.