Bash get script name, path, and directory (get script dir reliably)

Bash get script name, get current script name, get script path, and get script directory (script dir). Use $0, basename, BASH_SOURCE[0], dirname, cd+pwd, and readlink -f on Linux; handle sourced scripts safely.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Bash get script name, path, and directory (get script dir reliably)

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):

bash
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:

text
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.sh

Bash 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:

bash
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:

bash
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:

bash
source /tmp/example.sh   # inside the file: $0 is bash, BASH_SOURCE[0] is /tmp/example.sh

That 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.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …