Why can't I work with files in ".." from a symbolic link?
I have the following directory structure:
misha@misha-lmd:~/tmp$ ls -l
total 4.0K
-rw-r--r-- 1 misha lmd 21 Feb 18 21:00 hello.py
lrwxrwxrwx 1 misha lmd 20 Feb 18 21:01 symlink -> /home/misha/nobackup/
Next, I'll try the following:
misha@misha-lmd:~/tmp$ cd symlink
misha@misha-lmd:~/tmp/symlink$ cat ../hello.py
cat: ../hello.py: No such file or directory
Why doesn't it work?
If I do this instead:
misha@misha-lmd:~/tmp/symlink$ cd ..
misha@misha-lmd:~/tmp$ cat hello.py
print "Hello World!"
Then everything is fine. cd handles .. correctly, but cat doesn't. What is this witchcraft, and how can I make everything work the way I want?
EDIT
Ok, thanks to some of the answers here, I found out a little more about what's going on. First, it cd
's not actually executable, it's a shell builtin (in this case bash):
misha@misha-lmd:~/tmp$ type cd
cd is a shell builtin
If you are man bash
, you can find everything about the environment variables that bash uses for its household, including moving directories. There are other built-in modules, such as pwd
those that have counterparts that are actually executables:
misha@misha-lmd:~/tmp/symlink$ type pwd
pwd is a shell builtin
misha@misha-lmd:~/tmp/symlink$ /bin/pwd
/home/misha/nobackup
misha@misha-lmd:~/tmp/symlink$ /bin/pwd -L
/home/misha/tmp/symlink
The executable /bin/pwd
prints the default physical path, but it can also print the logical path specified by the `-L 'switch. Similarly, when I try to do:
misha@misha-lmd:~/tmp/symlink$ cat ../hello.py
cat: ../hello.py: No such file or directory
an error occurs because it is ..
interpreted as a physical parent directory and not a logical one. This allows me to clarify my question as:
When I specify a command line argument for an executable, how can I get ..
to refer to the logical parent and not the physical?
source to share
It doesn't work because it doesn't /home/misha/hello.py
. A symbolic link does not create a new directory, but points to a linked one. So when you connect to a symbolic link, you are actually connecting to that directory,
Did you expect the shell to remember where you came from from the symlink? Well, it doesn't work like that :)
source to share
Try
cat $(cd ..; pwd)/hello.pycat
Don't know if this helps you.
EDIT:
If you really need it , here's a way to do it (but it's kind of ugly):
$ lcat ( ) ( cd "${1%/*}"; cat "${1##*/}"; )
# use it like 'cat'
$ lcat ../hello.py
Using a function ( ... )
instead of a { ... }
body makes it cd
a subclass instead of the current wrapper.
When I try, it works with "filename completion" too.
But this solution is only cat
, it might be more difficult to use for other commands as I think.
$ lcmd ( ) ( local cmd="$1"; shift; cd "${1%/*}"; $cmd "${1##*/}"; )
Then, for example, lcmd cat ../hello.py
source to share