Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

2 Answers 2

up vote 13 down vote accepted

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.
share|improve this answer
    
I'm not sure to understand where does come from those differences –  user3581976 Jul 19 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 at 17:13
    
@user3581976: See my updated for more clearly. –  cuonglm Jul 19 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? –  user3581976 Jul 19 at 17:30
1  
@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 at 17:48

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.

share|improve this answer
    
Thanks, very good answer, this is what I was waiting for ;) –  user3581976 Aug 1 at 21:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.