Home > Back-end >  How do I convert relative directory names to absolute ones recognized by Bash?
How do I convert relative directory names to absolute ones recognized by Bash?

Time:12-04

When I input a relative directory path name using the 'read' command in Bash, it is not recognized as a valid directory by the -d test:

Relative directory path ~/tmp fails the if/-d test:

corba@samwise:~$ read CMDLINE_FILENAME
~/tmp
corba@samwise:~$ echo "$CMDLINE_FILENAME"
~/tmp
corba@samwise:~$ if [ -d $CMDLINE_FILENAME ]; then echo "Valid directory!"; fi
corba@samwise:~$

Relative directory path ../tmp fails the if/-d test:

corba@samwise:bin$ read CMDLINE_FILENAME
../tmp
corba@samwise:bin$ echo "$CMDLINE_FILENAME"
../tmp
corba@samwise:bin$ if [ -d $CMDLINE_FILENAME ]; then echo "Valid directory!"; fi
corba@samwise:~$

But an absolute directory path succeeds:

corba@samwise:~$ read CMDLINE_FILENAME
/home/corba/tmp
corba@samwise:~$ echo "$CMDLINE_FILENAME"
/home/corba/tmp
corba@samwise:~$ if [ -d $CMDLINE_FILENAME ]; then echo "Valid directory!"; fi
Valid directory!
corba@samwise:~$

I expected if [ -d ~/tmp ] and if [ -d ../tmp ] to be recognized as valid directory names. They were not.

I tried the solution that was offered in How to manually expand a special variable (ex: ~ tilde) in bash, but it only works for tilde and not for other relative paths like ../, ../../, or ./

I tried the variations of quoting/double-quoting and single/double square brackets in the if statement and get the same error in all cases. And these errors occur on MSYS2 (Git Bash) and Ubuntu 22.

CodePudding user response:

~/tmp actually is an absolute path from the bash point of view. However this relies on bash to substitute the ~ to the user accounts home folder path, so to something like /home/users/someone/tmp which clearly is an absolute path. That is a buildin feature of the bash shell usually called "path expansion". A relative path would be something like ./tmp or just tmp, so something that has to be interpreted relative to the current working directory of the process.

That substitution does not get applied here apparently. You can use a slightly altered command to achieve what you are looking for by explicitly forcing such expansion in a sub shell command:

if [ -d `eval echo $CMDLINE_FILENAME` ]; then echo "Valid directory!"; fi

That one works for absolute and relative paths, but also for entries that rely on the bash path expansion:

bash:~$ read CMDLINE_FILENAME 
~/tmp
bash:~$ echo "$CMDLINE_FILENAME"
~/tmp
bash:~$ if [ -d `eval echo $CMDLINE_FILENAME`]; then echo "Valid directory!"; fi 
Valid directory!

This does carry the risk of miss usage, though: the eval directive is a pretty mighty tool ...

  • Related