many ignore the difference meaning of .. (dot dot) as an argument when used with ls
or cd
this leads to buggy coding and wrong parsing of arguments in scripts
let’s start with an example
$ mkdir $HOME/test $HOME/test/physical $HOME/test/foo $ cd $HOME/test/foo $ ln -s ../physical logical $ cd logical $ ls -l .. total 8 drwxr-xr-x. 2 oracle dba 18:01 foo drwxr-xr-x. 2 oracle dba 18:01 physical $ cd ..; ls -l total 0 lrwxrwxrwx. 1 oracle dba 18:01 logical -> ../physical $
Wait… how could cd ..; ls
and ls ..
have a different output?
Most programs except cd
use the physical path in arguments.
If you are in the physical directory $HOME/test/physical and you issue
program argument
it will behave the same as if you were in the logical path. This is somehow consistent, but confusing
Let’s try
$ cd $HOME/test/physical $ ls -l .. total 8 drwxr-xr-x. 2 oracle dba 4096 May 21 18:01 foo drwxr-xr-x. 2 oracle dba 4096 May 21 18:01 physical $ cd $HOME/test/foo/logical $ ls -l .. total 8 drwxr-xr-x. 2 oracle dba 4096 May 21 18:01 foo drwxr-xr-x. 2 oracle dba 4096 May 21 18:01 physical $
BINGO! I got the same output
Got it? The arguments are parsed using the physical path.
This does not relate to absolute or relative path. While most bug occurs with relative path, a relative path is neither logical nor physical. It is relative. Whether it relates to a physical or it relates to a logical path is the scope of this post.
Okay, we get now that most programs use the “filename” as if you were in the physical path.
Path | Logical | Physical |
---|---|---|
/home/user01/test/physical | /home/user01/test/physical | /home/user01/test/physical |
/home/user01/test/foo/logical | /home/user01/test/foo/logical | /home/user01/test/physical |
In most case, it makes no difference (which render the bugs less evident to trap). For instance browsing paths in dbca doesn’t do it right, but it is just a side note.
If you use /physicalpath/file or /logicalpath/file or ./file, it really doesn’t matter. It’s relevant with symbolic links on directories and relative path to parents.
So for instance if you want to change to the directory of the first argument it would be wrong to do
cd $(dirname $1)
because cd does use logical path and your program should NOT (to make it symlink-independent).
a not-properly documented (missing for instance on aix 7.2 cd manpage) way is to use the -P option
In Linux there is also a -e option which gives you a non-zero error code on non-existent current working directory (if you are in a path that does not exits, the cd -P won’t work but return 0 by default), but for now, just stick to -P
Let’s see
$ pwd
/home/user01/test/foo/logical
$ cd -P ..
$ pwd
/home/user01/test
wait, you change to .. and went two step back? this is not the default behavior of cd. The default behavior is -L
$ pwd
/home/user01/test/foo/logical
$ cd -L ..
$ pwd
/home/user01/test/foo
hmm… is that not easier? No way! this is just fine for cd (where you navigate to parent regarding to the logical working directory). But it is not the way the arguments are interpreted.
Apart from cd , there is another command that deals with symlink path hassle : pwd. Again, it is not really well documented (missing in Solaris 10 pwd manpage), but it has always been there.
$ pwd
/u01/users/oracle/test/foo/logical
$ pwd -L
/u01/users/oracle/test/foo/logical
$ pwd -P
/u01/users/oracle/test/physical
$
next time you use cp, ls, cat with a .. and symlinks, remember this post !
Last note, one may like to try the long option. Don’t!
$ man pwd | grep -- -P
-P, --physical
$ cd -P .
$ cd --physical .
-bash: cd: --: invalid option
cd: usage: cd [-L|-P] [dir]
$