A script’s current working directory and the directory containing the script are different concepts. pwd reports where the caller is working; it does not reliably report where the script file lives.
Bash: directory containing the script
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(
cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1
pwd -P
)"
printf 'Script directory: %s
' "$SCRIPT_DIR"
BASH_SOURCE[0] identifies the current Bash source file. dirname extracts its directory, and the subshell changes to that directory before pwd -P returns an absolute physical path. The caller’s directory is unchanged.
POSIX shell variant
#!/bin/sh
case $0 in
*/*) script_path=$0 ;;
*) script_path=$(command -v -- "$0") ;;
esac
SCRIPT_DIR=$(
CDPATH= cd -P -- "$(dirname -- "$script_path")" && pwd -P
) || exit 1
printf 'Script directory: %s
' "$SCRIPT_DIR"
This version is useful for scripts intended for /bin/sh. It handles a command found through PATH, but it deliberately does not attempt to follow every symbolic-link chain.
Important edge cases
- A sourced file should normally use the shell’s source-file feature; in Bash, that is
BASH_SOURCE. readlink -fcan resolve links on systems that provide it, but it is not portable to every Unix platform.- Quote every path. Spaces, wildcard characters, and leading hyphens are valid in filenames.
- A copied script can still discover the copied location; do not assume a fixed installation directory unless your deployment guarantees it.
The legacy version used which $0, which is inconsistent across platforms and can mis-handle aliases, shell functions, and unusual paths. Use the shell’s own command lookup and keep path expansion quoted.

Leave a Reply