How to tell if I'm actually in a symlink location from command line?
Solution 1
Depending on how your pwd
command is configured, it may default to showing the logical working directory (output by pwd -L
) which would show the symlink location, or the physical working directory (output by pwd -P
) which ignores the symlink and shows the "real" directory.
For complete information you can do
file "$(pwd -L)"
Inside a symlink, this will return
/path/of/symlink: symbolic link to /path/of/real/directory
Solution 2
Note that pwd
is actually a shell built-in. Depending on your shell and its configuration, results may change. For a more portable solution, you should use /bin/pwd
. Snippet from manual page:
NAME
pwd - print name of current/working directory
SYNOPSIS
pwd [OPTION]...
DESCRIPTION
Print the full filename of the current working directory.
-L, --logical
use PWD from environment, even if it contains symlinks
-P, --physical
avoid all symlinks
--help display this help and exit
--version
output version information and exit
If no option is specified, -P is assumed.
NOTE: your shell may have its own version of pwd, which usually supersedes the version described here. Please refer to your shell's documentation for
details about the options it supports.
In general, you can resolve the full canonical path of any file/directory using readlink -f
. readlink -f .
works similar to pwd -P
.
Solution 3
You really are in /home/cpm135/public_html/class
-- that's the only correct answer to the question of "what's my current working directory".
When you refer to /var/lib/class
... that's not really about where you are, but more about what path you used to get there.
When you run /bin/pwd
, it figures out your current working directory by looking at the . and .. directories (the ones listed at the top of ls -la
), working out which directory in .. matches up with . and then working backwards until .. and . refer to the same directory. Once it's done all that, it knows what your current working directory is.
When you run the pwd
shell built-in, it doesn't follow this procedure (though it might do some of it if needed) -- instead, it remembers the path that you took to get here. So each time you do a cd
command, your shell remembers that as part of the path to get where you are now, and pwd
prints out what it has calculated based on all the cd
commands you've done -- which may or may not be your actual working directory.
Things can get really weird when you do a ln -s . foo
and keep cd
ing into foo -- /bin/pwd
will say you're still in the same directory, but the shell builtin pwd
will say you're in /foo/foo/foo/foo/foo/foo
-- even though no such directory even really exists. (That said -- you probably can cd
into it.)
Another source of confusion there is if directories are renamed. /bin/pwd
will then pick up on the change immediately, but the built-in pwd
won't until you do something that tells it that the old directory name doesn't matter.
Solution 4
Essentially you are asking if there is to show actual path of the current working directory. Well, there is with python and os.getcwd()
function
What you see below is a small test from within "VirtualBox VMs" directory located in my home directory. In reality, it's a symlink to a different directory located on different hard drive, mounted at /mnt/HDD
.
bash-4.3$ file "$(pwd)"
/home/xieerqi/VirtualBox VMs: symbolic link to /mnt/HDD/VirtualBox VMs/
bash-4.3$ python -c 'import os; print os.getcwd()'
/mnt/HDD/VirtualBox VMs
As you can see, python's os.getcwd()
resolves the real path of the directory, not the path of symlink.
Related videos on Youtube
Oliver Williams
Updated on September 18, 2022Comments
-
Oliver Williams almost 2 years
Suppose I have a folder:
cd /home/cpm135/public_html
and make a symbolic link
ln -s /var/lib/class .
Later, I'm in that directory:
cd /home/cpm135/public_html/class
The
pwd
is going to tell me I'm in/home/cpm135/public_html/class
Is there any way to know that I'm "really" in
/var/lib/class
? Thanks-
Admin over 7 years
-
Admin over 7 yearsSome shells don't actually allow you to be inside a symlink. For example, the
fish
shell automatically resolves the symlink when youcd
into it.
-
-
Oliver Williams over 7 yearsyes, the
-P
flag was what I needed. Thanks -
abligh over 7 yearsAlthough I've learnt the hard way that
readlink -f
is not available on all Unices (e.g. not available on OS-X) -
Dmitry Grigoryev over 7 yearsYou're not answering the question, you're dismissing it.
-
Anthony Geoghegan over 7 yearsWhile this doesn't answer the question directly, I think it's a useful post for understanding the difference between the shell's
pwd
builtin and/bin/pwd
and explaining how the stand-alone version provides more useful information (which can answer the original question). -
Arronical over 7 yearsThis answers the question perfectly without the need to echo. If the question was 'How do I display a message if I'm in a symlinked directory?" then echo would be required.
-
dougmc over 7 yearsThe question is based on an incorrect premise -- 'is there any way to know that I'm "really" in /var/lib/class?' That said ... by explaining what that really means, it helps him understand what he's really looking for. The pwd -P and -L options had already been mentioned ...
-
Peter Cordes over 7 years
file "$(pwd)"
only works if the symlink is the last directory component. It doesn't detect the OP's symlink when CDed to/home/cpm135/public_html/class/foo/bar
. I'm not aware of anything that prints info for all the symlinks in a pathname, but you can also userealpath .
, which I think is equivalent topwd -P
-
Peter Cordes over 7 yearsYou have your argument backwards.
ls ..
will show the contents of/var/lib
, not/home/cpm135/public_html
.cd ..
is special: the shell does special tracking of "how you got there" and doesn't actually make achdir("..")
system call. As far as the kernel is concerned, your shell's current working directory (/proc/self/cwd
) is just a mountpoint:inode pair. It's like an open file descriptor on the directory, which is why renaming the directory doesn't break your shell. (cd .
to update the shell's$PWD
variable). You're making a useful point, so I'd upvote this when fixed -
Peter Cordes over 7 years@IMSoP:
/bin/pwd -L
just prints the$PWD
environment variable. Without that, there's no way for a process to figure out its "logical" current working directory, because that isn't a real thing. It doesn't affect what you get from relative paths that start with../
, for example.strace /bin/pwd -P
(the default) just makes agetcwd(2)
system call. It doesn't trace up the..
links itself listing the directories to find matching inode numbers. It would be possible for the kernel to track "logical" paths, but it doesn't. -
IMSoP over 7 years@PeterCordes This answer talks about
/bin/pwd
and the shell doing different things, but other answers point out that both implementations have 2 modes, just different defaults. So if there really is a different algorithm used by the shell (which shell?) which mode is it for? Are there 3 different algorithms here, one for-L
and two different ways of implementing-P
? And when does it make a difference? I just tested the example given ofln -s . foo
, and/bin/pwd
and bash's builtin agree on the answer in both modes, as long as you specify the option rather than relying on the default. -
Peter Cordes over 7 years@IMSoP: AFAIK, nothing except shells and
/bin/pwd
look at the$PWD
environment variable. IDK why/bin/pwd
even has a-L
option, except maybe for compatibility with the shell built-in. Unless checking$PWD
is starting to catch on for use in file-selectors or something by programs started from the shell, it's still meaningless outside the shell. (But a child shell will inherit it, so it makes sense to have it in the environment). -
Peter Cordes over 7 years@IMSoP: no, I don't think there are multiple ways of implementing
-P
. They probably all call the POSIXgetcwd()
function, which (on Linux at least) is equivalent to traversing the..
links up to/
and checking finding the directory you came from in each higher directory, but much more efficient. -
IMSoP over 7 years@PeterCordes Why does it have the option? For predictability: you need to be able to know that
pwd
will behave a certain way, regardless of whether it resolves to the shell implementation or the binary. So I guess historically, shell built-ins worked one way, and binaries the other, and then they standardised to both include both modes. I stand by my comment that as currently implemented, it's more useful to talk about the two modes and which is the default than to assert that there is a fundamental difference in how the shell built-in works. -
Peter Cordes over 7 years@IMSoP: I never asserted that. I just said that dougmc has it backwards, and the
pwd -P
path is the closest to the "correct" answer to where you are. (But really, your cwd doesn't have to have a name, e.g. if it's an unlinked directory. It still has an inode-number though, which is what the kernel really tracks). -
Peter Cordes over 7 years@IMSoP: I just checked, POSIX requires the
pwd
command to support-P
and-L
(use$PWD
if it refers to the current directory and is canonical). Other than from a shell or shell script, it doesn't really make sense to runpwd
, so I didn't see much of a use-case for it (and didn't realize the-L
and-P
options were standardized). But obviously since POSIX requires it, the coreutils implementation needs to do it so it can support use-cases like perl backticks or whatever. -
dougmc over 7 yearsI don't have it backwards -- but yes, I was referring to the default usage of /bin/pwd and the default shell built-in pwd, which do indeed have different defaults (at least for most shells, regarding the shell version.) But yes, "pwd -P" would give a more "fundamental" answer than "pwd -L" I also really wasn't trying to be Linux specific ... this question and similar ones have been asked for longer than Linux has been around.