The fact you navigated to the current working directory by following some symbolic link(s) is only tracked by your shell, i.e. by Bash. The path that led you here is called the logical path, it can contain directory components that are in fact symbolic links to directories. The path after resolving all the symbolic links is called the physical path.
A tool that is neither your current Bash nor any of its builtins, when it gets spawned as a separate process in the current working directory of the shell, it knows the physical path to the directory naturally, because the physical path is the one the OS associates with the process (/proc/self/cwd
for the process). The tool can know the logical path by examining the PWD
variable in its environment or by using anything that examines the variable. The value of the variable comes from your Bash.
In Bash the builtins cd
and pwd
can operate on physical or logical paths, see this answer. pwd
that is not a builtin (e.g. /usr/bin/pwd
) can tell you the logical path only because it checks the PWD
variable in its environment. In a symlinked directory compare these:
$ env pwd -L
/logical/path
$ env pwd -P
/physical/path
$ env --unset=PWD pwd -L
/physical/path
Note all these pwd
s are not builtins; env
itself in not a shell builtin and it can only run pwd
executables, not builtins. By removing PWD
from the environment we made pwd -L
behave like pwd -P
.
ls
does not care about PWD
in the environment. The possible discrepancy between the physical and the logical path is irrelevant for what ls
does. You may have thought it should be different. In the first version of your question you made an incorrect assumption that all files in a symlinked directory are symlinks; with this assumption it's easy to further assume ls
hides this fact. The truth is ls
in some (physical) directory works in the same way, no matter what logical path led your shell to the directory.
You can detect discrepancy between the physical and the logical path by comparing the output of pwd -P
to the output of pwd -L
(or directly to $PWD
). Let's build a basic warning into ls
:
function ls (
p="$(pwd -P)"
command ls "$@"
[ "$p" != "$PWD" ] && >&2 printf 'ls: warning: ./ -> %s/\n' "$p"
)
I used a function, not an alias, because alias ls='ls --color=auto'
is quite common and I don't want to break it; also because aliases are not for this. The highly probable existence of the alias makes the syntax function ls …
way better than the portable ls () …
(the latter triggers the alias).
This basic function is not perfect. ls /some/other/dir
will never warn you about /some/other/dir
, it will warn you about ./
(if symlinked) in spite of ./
being irrelevant in this case.
Anyway, the answer to "how could I know that I am in a subdirectory that is a (grand-…)child of a symlinked directory?" is:
[ "$(pwd -P)" != "$PWD" ]
realpath
? – Aaron D. Marasco Aug 16 '20 at 21:22