How can I determine the directory path of a Bash script from within the script itself, and then change the working directory to that location?
How to Determine and Change to a Bash Script’s Directory
Brief answer: To determine a Bash script’s directory path and change to it, use SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
to get the absolute path, then cd "$SCRIPT_DIR"
to change to that directory. This approach handles symlinks and works for both executed and sourced scripts.
Contents
- How to Get the Script’s Directory Path
- Changing to the Script’s Directory
- Handling Common Edge Cases
- Practical Examples and Use Cases
How to Get the Script’s Directory Path
There are several ways to determine the directory path of a Bash script, each with different advantages and use cases:
The Most Reliable Method
The most robust approach uses BASH_SOURCE
with dirname
and pwd
:
#!/bin/bash
# Get the directory where the script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "Script directory: $SCRIPT_DIR"
This method:
- Uses
BASH_SOURCE[0]
which is more reliable than$0
- Handles symlinks properly
- Works for both executed and sourced scripts
- Returns an absolute path
Alternative Methods
Using $0
with dirname
#!/bin/bash
SCRIPT_DIR="$(dirname "$0")"
echo "Script directory: $SCRIPT_DIR"
This simpler approach has limitations:
- Might return relative path if script is called with relative path
- Doesn’t resolve symlinks
- Behaves differently when script is sourced
Resolving Symlinks
If you need to resolve symlinks to the actual script location:
#!/bin/bash
SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
echo "Script directory (resolving symlinks): $SCRIPT_DIR"
The -f
flag to readlink
follows all symbolic links to return the canonical path.
Changing to the Script’s Directory
Once you have the script directory path, changing to it is straightforward:
#!/bin/bash
# Get the script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Change to the script directory
cd "$SCRIPT_DIR" || {
echo "Error: Cannot change to directory $SCRIPT_DIR" >&2
exit 1
}
# Now you're in the script's directory
echo "Current working directory: $(pwd)"
Error Handling
Always check if the directory change was successful:
if ! cd "$SCRIPT_DIR"; then
echo "Failed to change to script directory: $SCRIPT_DIR" >&2
exit 1
fi
Preserving Original Directory
If you need to return to the original directory later:
#!/bin/bash
# Get original directory
ORIGINAL_DIR="$(pwd)"
# Get and change to script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" || exit 1
# Do work in script directory...
# Return to original directory
cd "$ORIGINAL_DIR"
Handling Common Edge Cases
Sourced vs. Executed Scripts
The BASH_SOURCE
array is specifically designed to handle both scenarios:
#!/bin/bash
# Works whether script is executed or sourced
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "Script is being executed"
else
echo "Script is being sourced"
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Relative vs. Absolute Paths
The $(cd ... && pwd)
pattern ensures you always get an absolute path:
#!/bin/bash
# This will always return an absolute path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "Absolute path: $SCRIPT_DIR"
Directory with Spaces
Handle directories with spaces by properly quoting variables:
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Always quote variables when using them with cd
cd "$SCRIPT_DIR" || exit 1
Practical Examples and Use Cases
Complete Script Example
Here’s a complete script that demonstrates both getting the directory and changing to it:
#!/bin/bash
# Function to get script directory
get_script_dir() {
cd "$(dirname "${BASH_SOURCE[0]}")" && pwd
}
# Get the script directory
SCRIPT_DIR=$(get_script_dir)
echo "Script directory: $SCRIPT_DIR"
# Change to script directory with error handling
if ! cd "$SCRIPT_DIR"; then
echo "Error: Failed to change to script directory" >&2
exit 1
fi
# Now you can reliably reference files relative to the script
echo "Listing files in script directory:"
ls -la
# Example: Reading a config file in the same directory
if [[ -f "config.conf" ]]; then
echo "Reading config file..."
source config.conf
else
echo "Warning: config.conf not found" >&2
fi
Reusable Function
For scripts that need this functionality multiple times:
#!/bin/bash
# Function to change to script directory
# Returns 0 on success, 1 on failure
change_to_script_dir() {
local script_dir
script_dir="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)" || return 1
if ! cd "$script_dir"; then
echo "Error: Cannot change to directory $script_dir" >&2
return 1
fi
return 0
}
# Example usage in another function
setup_environment() {
if ! change_to_script_dir; then
return 1
fi
# Now we're in the script's directory
echo "Setting up environment in $(pwd)"
# Additional setup code...
return 0
}
# Call the function
setup_environment
Using in Larger Scripts
For larger projects, you might want to store the script directory as a global variable:
#!/bin/bash
# Get script directory at the start
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Function to ensure we're in the script directory
ensure_script_dir() {
if [[ "$(pwd)" != "$SCRIPT_DIR" ]]; then
echo "Changing directory to $SCRIPT_DIR" >&2
if ! cd "$SCRIPT_DIR"; then
echo "Error: Failed to change to script directory" >&2
return 1
fi
fi
return 0
}
# Call this function before operations that rely on being in the script directory
if ! ensure_script_dir; then
exit 1
fi
# Rest of the script...
Conclusion
To determine and change to a Bash script’s directory:
- Use
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
to get the absolute path of the script’s directory - Use
cd "$SCRIPT_DIR"
to change to that directory, with proper error handling - Always quote variables when using them with
cd
to handle spaces and special characters - Consider using
BASH_SOURCE
instead of$0
for better reliability, especially with sourced scripts - For complex scripts, create reusable functions or store the directory as a readonly variable
This approach ensures your script works consistently regardless of how it’s invoked or where it’s located in the filesystem.