Shell scripts often need their own location: resolving includes, writing logs next to the script, or changing to a known directory. In practice you want the file name, the full path, and the directory that contains the script—the things people describe as bash get script name, bash get script path, bash get script directory, or bash get script dir.
Tested the snippets in this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37 (2026-06-13).
Bash get script name and bash get current script name
$0 is how the shell was invoked: it may be a relative path (./deploy.sh), an absolute path (/opt/app/deploy.sh), or even -bash in a login shell. It is fine for a quick echo, but it is not always the path of the file that contains the current code—especially when a file is sourced.
For code that must work when the file is executed or sourced, prefer ${BASH_SOURCE[0]} (the current file in the call stack). From a file run as the main program, it behaves like a stable “this file” handle.
Name only (works with spaces if you quote):
script_basename=$(basename -- "${BASH_SOURCE[0]}")
echo "$script_basename"I ran a tiny script from /tmp in two ways. With bash /tmp/demo.sh, $0 and BASH_SOURCE[0] both showed the absolute path. With ./demo.sh from /tmp, $0 stayed relative while readlink -f "${BASH_SOURCE[0]}" still produced the canonical path. Illustrative output:
argv0=$0 => /tmp/demo.sh
BASH_SOURCE[0]=/tmp/demo.sh
basename => demo.sh
dirname $0 => /tmp
SCRIPT_DIR cd+pwd => /tmp
readlink -f BASH_SOURCE => /tmp/demo.sh
argv0=$0 => ./demo.sh
BASH_SOURCE[0]=./demo.sh
basename => demo.sh
dirname $0 => .
SCRIPT_DIR cd+pwd => /tmp
readlink -f BASH_SOURCE => /tmp/demo.shBash get script directory and bash get directory of script
dirname strips the last path component. dirname "$0" alone returns a path relative to how you launched the script (dirname ./tool.sh is .), which is not always what you want for bash get script directory.
A common Linux pattern is: resolve the script’s directory, cd there, then print pwd:
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" && pwd)
echo "$script_dir"Here cd -- avoids edge cases where a directory name starts with -, and "${BASH_SOURCE[0]:-$0}" falls back to $0 on very old Bash if needed.
Avoid script_dir=$(pwd)/$(dirname "$0") (or the same idea with $PWD). If the script lives under /opt/foo/bar.sh but you run it from your home directory, pwd is your home while dirname "$0" is /opt/foo; concatenating them produces a path that does not exist.
Bash get script path (canonical / absolute)
GNU readlink -f resolves symlinks and prints a single absolute path, which is what many people mean by bash get script path:
script_path=$(readlink -f -- "${BASH_SOURCE[0]}")
echo "$script_path"If readlink -f is unavailable, realpath from GNU coreutils is a close substitute on modern Linux. Both follow the final file target; combine with dirname if you only need the directory.
For background on symlinks themselves, see create a symbolic link on Linux.
Sourced scripts: $0 vs BASH_SOURCE
When you source a file, $0 names the shell (for example bash), not the file. ${BASH_SOURCE[0]} still points at the file that contains the running line:
source /tmp/example.sh # inside the file: $0 is bash, BASH_SOURCE[0] is /tmp/example.shThat is why BASH_SOURCE[0] is the safer default for libraries and scripts that may be sourced from a parent.
Why $_ is a poor way to bash get script name
$_ expands to the last argument of the previous command. It can look like the script path when you run ./script.sh, but with bash script.sh it is often the path to the bash binary instead—the “previous command” was bash, and its last argument may not be what you expect. For predictable behavior, use BASH_SOURCE[0] (or $0 when you know the file is never sourced). For how Bash passes arguments in general, see bash script multiple arguments.
Summary
Use basename -- "${BASH_SOURCE[0]}" when you only need the file label (often described as bash get script name or bash script name). For bash get script directory, bash get directory of script, or bash get script dir, resolve BASH_SOURCE[0] (or $0 when you never source the file), cd to that directory, and print pwd, or run dirname on a path you already canonicalized with GNU readlink -f. That gives a dependable bash get script path without the old pwd/dirname concatenations that break when the script lives outside the current working directory.
Prefer BASH_SOURCE[0] whenever the file might be sourced so bash get current script name and directory still refer to the library file instead of the parent shell’s $0.
Further reading: Bash manual — special parameters, Greg’s BashFAQ 028 — where is my script?, and the Bash Guide on parameters.

