17

I added a symlink to the current directory with ln -s . aa. If I execute cd aa, and after that I executed pwd, the response is /home/sim/aa.

But if I execute /bin/pwd it prints /home/sim (the current directory hasn't changed).

Where does this difference come from?

2 Answers 2

18

In most shells including bash, pwd is a shell builtin:

$ type -a pwd
pwd is a shell builtin
pwd is /bin/pwd

If you use /bin/pwd, you must use the -L option to get the same result as builtin pwd:

$ ln -s . test
$ cd test && pwd
/home/cuonglm/test
$ /bin/pwd
/home/cuonglm
$ /bin/pwd -L
/home/cuonglm/test

By default, /bin/pwd ignores symlinks and prints the actual directory.

From info pwd:

`-L'
`--logical'
     If the contents of the environment variable `PWD' provide an
     absolute name of the current directory with no `.' or `..'
     components, but possibly with symbolic links, then output those
     contents.  Otherwise, fall back to default `-P' handling.

`-P'
`--physical'
     Print a fully resolved name for the current directory.  That is,
     all components of the printed name will be actual directory
     names--none will be symbolic links.

The built-in pwd includes symlink by default, except that -P option is used, or -o physical set builtin is enabled.

From man bash:

pwd [-LP]
              Print the absolute pathname of the  current  working  directory.
              The pathname printed contains no symbolic links if the -P option
              is supplied or the -o physical option to the set builtin command
              is  enabled.  If the -L option is used, the pathname printed may
              contain symbolic links.  The return status is 0 unless an  error
              occurs  while  reading  the  name of the current directory or an
              invalid option is supplied.
8
  • I'm not sure to understand where does come from those differences Jul 19, 2014 at 17:10
  • /bin/pwd ignores symlink by default, read part info pwd in my answer: Print a fully resolved name for the current directory. That is, all components of the printed name will be actual directory names--none will be symbolic links.
    – cuonglm
    Jul 19, 2014 at 17:13
  • @user3581976: See my updated for more clearly.
    – cuonglm
    Jul 19, 2014 at 17:19
  • Why is there a -L command for pwd although it is set by default? And doesn't the shell use the /bin/pwd command to run pwd? Jul 19, 2014 at 17:30
  • 2
    @user3581976: Image that you start your shell with set -o physical, now pwd is use -P option by default, if you don't have -L option, how do you print the path contains symlink? Read this https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html to know what set -o physical does.
    – cuonglm
    Jul 19, 2014 at 17:48
8

It is possible for a process to interrogate the file system to determine its current working directory, using a method that’s a little too complicated to be on topic as an answer to this question.  This is what the pwd program and the getcwd library function do.  In the early days of Unix, they were the only ways to find out what your working directory was.  Here’s the part of the answer to your question that I can’t find in any of the other answers, or even anywhere else on this site (after 42 seconds’ worth of searching):

  • When the shell starts, it gets its current working directory (probably by calling getcwd).
  • Thereafter, whenever you do a cd, pushd, or popd, the shell keeps track of the working directory using string manipulation functions. For example,

    • If your working directory is /home/sim and you type cd .., the shell computes that your working directory is /home.
    • If your working directory is /home/sim and you type cd ., the shell computes that your working directory is still /home/sim.
    • If your working directory is /home/sim and you type cd aa, the shell computes that your working directory is /home/sim/aa – without checking to see whether aa is a symbolic link.

    It does this to save the “cost” of calling getcwd.  But this is a trade-off, since it can result in incorrect information.

  • The pwd (builtin) command simply displays the shell’s remembered/computed notion of what the working directory is.
  • Also, the shell puts its remembered/computed notion of what the working directory is into the PWD environment variable, for the convenience of user processes.  A process should never rely on this if it wants accurate information.

So, the bottom line is that the shell can get confused about where it is.  But if you type /bin/pwd, that runs in a separate process that doesn’t have access to the shell’s notion of what the working directory is, and so it determines the true working directory itself, the old-fashioned way.  (Exception: the /bin/pwd program can look at the PWD environment variable, and apparently it does when you specify -L.)  Here’s another example of how the shell can get confused:

cd /home/sim/aa # Assume that /home, /home/sim,  and /home/sim/aa
# are all real directories (not symbolic links).
pwd # Output: /home/sim/aa, which is correct.
mv ../aa ../bb
pwd # Output: /home/sim/aa, which is incorrect.
/bin/pwd # Output: /home/sim/bb, which is correct.


And, just in case you’re not clear on this, if you type ln -s . aa and cd aa, then your current working directory hasn’t changed, any more than it does when you type cd . – because, that’s essentially what you’re doing when you type cd aa.

4
  • Thanks, very good answer, this is what I was waiting for ;) Aug 1, 2014 at 21:37
  • 2
    This answer seems a little bent. There's more to -L than saving cost - and $PWD is a user-defined POSIX-specified environment variable - user-space applications should probably trust it (whatever that means...?). Anyway, while I'm not at all a fan of symlinks, it is the user's prerogative to indirect in as many crazy directions as he or she should choose with them - and that's what -L is about more than anything.
    – mikeserv
    Mar 18, 2015 at 5:12
  • 1
    This should be the accepted answer (the symbolic links aren't the point of the question). Nov 25, 2016 at 2:18
  • This is more helpful than the accepted answer IMO. So /bin/pwd is like the true working directory, whereas pwd just shows you your working directory relative to where you started the shell?
    – Lou
    Nov 10, 2020 at 10:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .