tags:

views:

115

answers:

5

I have been trying to figure out how a shell knows which directory you're currently in. I know there is an environment variable $PWD but when I try changing it manually, it changes what my shell shows at the prompt but commands like ls and cd are unaffected.

cd is an internal shell command so I can understand it might use info stored within the shell memory, but ls is external and yet running ls without anything will give me whatever directory I was originally in regardless what I do to $PWD.

+9  A: 

The shell sets that variable, but stores the knowledge internally (which is why you can't make cd an external program, it must be a built-in). The shell prompt is composed just before it is displayed each time, and you have specified using $PWD in yours, so the shell reads that in.

Remember: the shell is just a program, like any other program. It can---and does---store things in variables.


As AndiDog and John point out unix-like systems (i.e. including linux) actually maintains the working directory for each process through a set of system calls. The storage is still process local, however.

dmckee
this is exactly the right answer.
Ian
+1  A: 

You (OP) launch ls via your command shell, and any process you launch, the shell launches in the context of its current working directory. So, each process you launch has its own $PWD variable (in a way).

Vermiscious
There is a rarely used argument to main(int argc, char **argv, char **envp), it used to be the third parameter, that the environment was copied into main by the os starting the process, this is dropped now as most systems do it automatically...
tommieb75
+11  A: 

Each process has its own individual current working directory which the Linux system tracks. This is one of the pieces of information the OS manages for each process. There is a system call getcwd() which retrieves this directory.

The $PWD environment variable reflects what getcwd() was the last time the shell checked, but this explains why changing it does not actually change the current directory. To do that the shell would have to call chdir() when $PWD changes, which it does not do.

This also is the reason cd has to be a shell built-in. When you run a sub-process that child process gets its own working directory, so if cd were an executable then its calls to chdir() would be useless as that would not change its parent's working directory. It would only be changing its own (short-lived) working directory. Hence, cd is a shell built-in to avoid a sub-process being launched.

John Kugelman
prefect! thanks
P M
A fun aside: according to *A Quarter Century of UNIX* (I think), in *really* old Unix, `chdir` actually *was* an external process. That's because there was no `wait`, the shell merely `exec`ed the programs it ran, and then the shell was re-`exec`'d on exit. This meant that `/bin/chdir` could simply `chdir()` and then re-`exec` the shell, which would inherit the new CWD. :)
hobbs
Oops, my backticks ran out of control and it's too late to edit ;)
hobbs
Linux (Solaris, ...) have /proc filesystems where you can actually "see" this stuff. To get your shell's cwd, `ls -ld /proc/$$/cwd` (the shell substitutes it's process id for $$).
Tony
+3  A: 

The Linux kernel stores the current directory of each process. You can look it up in the /proc filesystem (for example, "/proc/1/cwd" for the init process).

The current directory can be changed with the chdir syscall and retrieved with getcwd.

AndiDog
+1  A: 

The current directory is a property of a running program (process) that gets inherited by processes created by that process. Changing the current directory is made via an operating system call. The shell maps the cd operation to that system call. When you write an external program like ls, that program inherits the current directory.

The $PWD variable is how the shell shows you the current directory for you to use it as a variable if you need it. Changing it does not have effect in the real current directory of the shell itself.

Diego Sevilla