Guides

pwd command: print working directory, -L vs -P and $PWD

The pwd command prints the directory your shell is in. -L vs -P with symlinks, $PWD and $OLDPWD, cd -, and how a script finds its own directory.

Published ~5 min read
On this page

Short answer: the pwd command (print working directory) prints the full, absolute path of the directory your shell is in right now, such as /home/deploy/site. If you got there through a symbolic link, plain pwd shows the path through the link; pwd -P resolves every link and shows where you physically are.

any Linux
cd /var/log
pwd
Output
/var/log

The Linux examples below were checked on Debian 12 with bash 5.2.15 and GNU coreutils 9.1; the sudo and Windows notes follow their documentation.

TaskCommand
Print the current directorypwd
Logical path, through symlinks (bash default)pwd -L
Physical path, symlinks resolvedpwd -P
The same value as a variableecho "$PWD"
The directory you were in beforeecho "$OLDPWD"
Go back to the previous directorycd -
Directory of the running scriptdirname "$(realpath "$0")"

Two pwds: the shell builtin and /bin/pwd

bash
type -a pwd
Output on Debian 12
pwd is a shell builtin
pwd is /usr/bin/pwd
pwd is /bin/pwd

Typing pwd runs the version built into bash (dash and zsh have one too). The separate program from coreutils exists for scripts and tools that call it directly. They print the same path almost always, with one difference that matters below: the bash builtin defaults to -L, while /bin/pwd defaults to -P.

pwd -L vs pwd -P: symlinks

Symlinked directories are common on servers. A deploy script that keeps releases side by side and points a current link at the live one is a typical case:

bash
mkdir -p ~/site/releases/2026-10-21
ln -sfn releases/2026-10-21 ~/site/current
cd ~/site/current
pwd
pwd -P
/bin/pwd
Output (as user deploy)
/home/deploy/site/current
/home/deploy/site/releases/2026-10-21
/home/deploy/site/releases/2026-10-21

-L (logical) reports the path the way you typed it on the way in, links and all. bash tracks it in $PWD, which is also why cd .. from current returns to ~/site rather than to ~/site/releases. -P (physical) asks the kernel where the directory really is. Use -P when the real location matters: checking which release is live, comparing two paths, or before deleting something.

$PWD, $OLDPWD and cd -

Every cd updates two shell variables: $PWD holds the new directory (the same value pwd prints) and $OLDPWD the one you just left. cd - swaps the two and prints where it took you, which makes jumping between a config directory and a log directory a single keystroke each way:

bash
cd /etc/nginx/sites-available
cd /var/log/nginx
cd -          # prints /etc/nginx/sites-available
cd -          # prints /var/log/nginx

In a script, "$PWD" is cheaper than $(pwd) because it starts no subshell, and the two hold the same value.

The directory in your prompt

Debian and Ubuntu set a default prompt (in /etc/bash.bashrc and the default ~/.bashrc) that already shows the working directory through the \w escape, which is why you rarely need pwd at an interactive shell:

Prompt
deploy@vps:~/site/current$

Two limits make pwd worth typing anyway: \w shortens your home directory to ~, and it shows the logical path, so the prompt never tells you that current is a link. On deep paths, PROMPT_DIRTRIM=2 in ~/.bashrc keeps only the last two directories in the prompt and replaces the rest with ...; \W instead of \w shows only the last directory name.

pwd in a script is not the script’s directory

A script inherits the working directory of whoever started it. pwd inside the script therefore prints the caller’s directory, not the directory the script file lives in, and every relative path in it breaks as soon as someone runs it from elsewhere. cron is the classic case: it starts jobs in the user’s home directory, one of the reasons behind a cron job that runs by hand but not on schedule. A small test script shows the difference:

~/app/bin/where.sh
#!/bin/bash
echo "pwd:          $(pwd)"
echo "dirname \$0:   $(dirname "$0")"
echo "script dir:   $(dirname "$(realpath "$0")")"
Output of app/bin/where.sh, run from /home/deploy
pwd:          /home/deploy
dirname $0:   app/bin
script dir:   /home/deploy/app/bin

dirname "$0" gives the path as it was typed, which can be relative, and when the script is started through a symlink it gives the directory of the link, not of the script. realpath fixes both. The line to put at the top of a script:

bash
script_dir=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
cd "$script_dir" || exit 1

${BASH_SOURCE[0]} also works when the file is sourced with source or ., where $0 is the name of the shell instead. It is a bash feature: under sh (dash on Debian and Ubuntu) it fails with Bad substitution, so a POSIX sh script uses $(dirname "$(realpath "$0")"). Remember to make the script executable with chmod +x before running it as ./script.sh.

pwd errors: a directory that no longer exists

If the directory you are standing in is deleted, for example by a deploy that removed an old release, the shell still remembers the path but the directory is gone:

Output
$ pwd -P
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
$ /bin/pwd
/bin/pwd: couldn't find directory entry in ‘..’ with matching i-node

Plain pwd keeps printing the old path from $PWD, which is misleading, and new shells started from there report shell-init: error retrieving current directory. The fix is to leave: cd to an absolute path. If the directory was recreated under the same name, cd "$PWD" moves you into the new one; a plain ls before that shows the old, empty directory.

  • pwd: -x: invalid option: bash’s builtin accepts only -L and -P.
  • The path changed after sudo. sudo -i starts a login shell and, per the sudo man page, changes to the target user’s home directory, so pwd shows /root. sudo -s keeps the current directory. More on setting up that account in creating a sudo user.

pwd on Windows and in sftp

In the Windows command prompt, cd with no arguments prints the current directory (echo %cd% does the same inside a batch file). PowerShell has Get-Location, with pwd and gl as built-in aliases and the automatic variable $PWD, per Microsoft’s PowerShell documentation. Inside an sftp session, pwd prints the remote directory and lpwd the local one.

Frequently asked

What does pwd stand for?

Print working directory. It prints the absolute path of the directory the current shell is in, which is the directory every relative path you type is resolved against.

What is the difference between pwd -L and pwd -P?

pwd -L prints the logical path, including any symbolic links you went through to get there. pwd -P resolves those links and prints the physical location. The bash builtin defaults to -L, while the standalone /bin/pwd from GNU coreutils defaults to -P, so the two can print different paths in a symlinked directory.

How do I get the directory of the script itself in bash?

script_dir=$(dirname "$(realpath "${BASH_SOURCE[0]}")"). pwd inside a script only shows the directory it was started from. realpath also resolves a symlink to the script, and BASH_SOURCE still works when the file is sourced. In a POSIX sh script, use $0 in place of ${BASH_SOURCE[0]}.

What is the Windows equivalent of pwd?

In Command Prompt, cd with no arguments prints the current directory. In PowerShell the command is Get-Location, and pwd works there too as a built-in alias for it.

Related articles

All guides