What does pwd output?

There are three independent "directories" at play here:

  1. your current shell's current working directory,
  2. the shell script's current working directory, and
  3. the directory containing the shell script.

To demonstrate that they are independent, you can write a shell script, saved to /tmp/pwd.sh, containing:

#!/bin/sh
pwd
cd /var 
pwd

You can then change your pwd (#1 above) to /:

cd /

and execute the script:

/tmp/pwd.sh

which starts off by demonstrating your existing pwd (#1), then changes it to /var and shows it again (#2). Neither of those pwd's were "/tmp", the directory that contains /tmp/pwd.sh (#3).


Present (or Current) Working Directory

Does the command pwd in a shell script return the directory the shell script is in?

No.

Firstly, by definition, no shell script or shell command returns anything other than a numeric exit status between 0 - 255. That's axiomatic, but not generally not what people mean when they ask these types of questions.

Secondly, pwd is both a Bourne shell builtin and a standard system binary. Either one prints the logical or physical current working directory, which is generally:

  1. Your location in the directory structure when you call a script or binary.
  2. Your current location after changing the working directory with cd or other utilities and builtins that modify the current working directory such as pushd or popd.

If you want the directory of the current script, use the dirname utility as described in the final section below.

Quick Test of pwd

As a quick test to see what pwd really prints, you can run the following:

# Create a shell script containing pwd.
cat <<-EOF > /tmp/test_pwd.sh
#!/bin/sh

pwd
EOF

# Make the script executable.
chmod 755 /tmp/test_pwd.sh

# Go somewhere on the filesystem, and call the test script.
cd /etc
/tmp/test_pwd.sh

This will print /etc, not /tmp, because your current working directory is currently /etc. This is the expected behavior.

Getting the Directory Containing a Script

You're probably asking this question because you want to find the directory of the current script. In the general case, the following is the quick-and-dirty solution:

#!/usr/bin/env bash
echo $(dirname "$0")

This works because $0 generally contains the pathname used to invoke the script being executed, and the shell expansion uses the dirname utility to return the path excluding the filename portion. You can do something similar, but less portably, with the Bash parameter expansion "${0%/*}".

This is all a vast over-simplification, of course. Please read the Bash manual (especially the sections on positional parameters, special parameters, and BASH_SOURCE) and the man pages for readlink and realpath to get a fuller understanding of what the edge cases are, of which there are several.

However, in day-to-day scripting, the directory component of $0 is sufficient to tell you what you want to know. If you are doing something complicated enough where $0 doesn't hold the information you actually need, and you require more complicated constructs like:

echo $(dirname "$(realpath "$0")")

then you're probably making your life more difficult than it needs to be.


pwd returns 0 unless its current working directory cannot be opened.

mkdir /tmp/d; cd "$_"
pwd && pwd -P; echo "$?"
rmdir ../d
pwd && pwd -P; echo "$?"

/tmp/d
/tmp/d
0
/tmp/d
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
1