Linux Command Reference

source

Synopsis

source filename [arguments] . filename [arguments]

Description

The source command (also invoked as .) reads and executes commands from a file in the current shell environment. This is a crucial distinction from running a script normally - when you execute a script directly, it runs in a subshell and any variable changes, function definitions, or directory changes are lost when the script completes. With source, everything happens in your current shell session.

This makes source essential for configuration files, environment setup scripts, shell function libraries, and any scenario where you need changes to persist in your current shell. It's commonly used with .bashrc, .profile, Python virtual environments, and custom configuration scripts.

Key Concepts

Detailed Examples

Example 1

Reload Shell Configuration (.bashrc)

The most common use of source - reloading your bash configuration after making changes. This allows you to apply new aliases, functions, or environment variables without logging out and back in.
# Edit your .bashrc vim ~/.bashrc # Add a new alias # alias ll='ls -lah --color=auto' # Reload the configuration in current shell source ~/.bashrc # Or using the dot notation (POSIX-compliant) . ~/.bashrc # Verify the alias is now available ll /tmp
Output:
# After sourcing, the 'll' alias is immediately available total 48K drwxrwxrwt 12 root root 4.0K Dec 14 13:45 . drwxr-xr-x 20 root root 4.0K Nov 28 09:12 .. drwxrwxrwt 2 root root 4.0K Dec 14 08:00 .X11-unix
Note:

Without source, you'd need to open a new terminal or log out/in to see the changes. Sourcing applies them immediately to your current session.

Example 2

Set Environment Variables Persistently

Create a script that sets environment variables and source it to make those variables available in your current shell. This is essential for development environments where you need specific configurations.
# Create an environment configuration file cat > ~/dev_environment.sh << 'EOF' #!/bin/bash # Development environment configuration export JAVA_HOME="/usr/lib/jvm/java-11-openjdk" export MAVEN_HOME="/opt/maven" export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH" export DB_HOST="localhost" export DB_PORT="5432" export DB_NAME="devdb" export LOG_LEVEL="DEBUG" echo "Development environment loaded" echo "JAVA_HOME: $JAVA_HOME" echo "DB_HOST: $DB_HOST" EOF # Make it executable (optional for sourced scripts) chmod +x ~/dev_environment.sh # Source it to load variables source ~/dev_environment.sh # Verify variables are set echo $JAVA_HOME echo $PATH | tr ':' '\n' | grep java
Output:
Development environment loaded JAVA_HOME: /usr/lib/jvm/java-11-openjdk DB_HOST: localhost /usr/lib/jvm/java-11-openjdk /usr/lib/jvm/java-11-openjdk/bin
Note:

If you ran this as ./dev_environment.sh instead of sourcing it, the variables would only exist in the subshell and disappear immediately. Source makes them persist in your current session.

Example 3

Activate Python Virtual Environment

Python virtual environments use source to activate. This is a perfect real-world example of why source is necessary - the activation script modifies your PATH and sets environment variables that must persist in your current shell.
# Create a Python virtual environment python3 -m venv myproject_env # Activate it using source source myproject_env/bin/activate # Or using dot notation . myproject_env/bin/activate # Your prompt changes to show (myproject_env) # Check which python is being used which python echo $VIRTUAL_ENV # Install packages (will go into the virtual environment) pip install requests # When done, deactivate (this is a function defined by activate script) deactivate
Output:
# After sourcing activate: (myproject_env) user@host:~$ which python /home/user/myproject_env/bin/python (myproject_env) user@host:~$ echo $VIRTUAL_ENV /home/user/myproject_env # After deactivate: user@host:~$ which python /usr/bin/python
Warning:

Running ./myproject_env/bin/activate WILL NOT WORK. The activate script must be sourced to modify your current shell's environment. This is why it's always source or .

Example 4

Load Shell Function Library

Create a library of reusable shell functions and source it into your current shell. This allows you to organize commonly-used functions separately and load them on demand.
# Create a function library cat > ~/shell_functions.sh << 'EOF' #!/bin/bash # Shell Function Library # Backup a file with timestamp backup_file() { if [ -z "$1" ]; then echo "Usage: backup_file <filename>" return 1 fi if [ ! -f "$1" ]; then echo "Error: File '$1' not found" return 1 fi local backup_name="${1}.backup.$(date +%Y%m%d_%H%M%S)" cp "$1" "$backup_name" echo "Backed up to: $backup_name" } # Create directory and cd into it mkcd() { mkdir -p "$1" && cd "$1" } # Extract various archive formats extract() { if [ -f "$1" ]; then case "$1" in *.tar.gz) tar xzf "$1" ;; *.tar.bz2) tar xjf "$1" ;; *.zip) unzip "$1" ;; *.gz) gunzip "$1" ;; *.tar) tar xf "$1" ;; *) echo "Unknown archive format" ;; esac else echo "File not found: $1" fi } # Find process by name findproc() { ps aux | grep -i "$1" | grep -v grep } echo "Shell functions loaded: backup_file, mkcd, extract, findproc" EOF # Source the library source ~/shell_functions.sh # Now use the functions backup_file /etc/hosts mkcd ~/test_directory findproc nginx
Output:
Shell functions loaded: backup_file, mkcd, extract, findproc Backed up to: /etc/hosts.backup.20251214_134523 # mkcd creates directory and changes to it user@host:~/test_directory$ # findproc shows matching processes root 1234 0.0 0.1 12345 6789 ? Ss Dec13 0:05 nginx: master process www-data 5678 0.0 0.2 23456 8901 ? S Dec13 0:12 nginx: worker process
Note:

Functions defined in a sourced script become available in your current shell. You can add source ~/shell_functions.sh to your .bashrc to load these functions automatically in every new shell.

Example 5

Source with Arguments

Pass arguments to a sourced script just like you would to a regular script. The arguments are available as positional parameters ($1, $2, etc.) within the sourced file.
# Create a configurable environment loader cat > ~/load_env.sh << 'EOF' #!/bin/bash # Load environment based on argument ENVIRONMENT="${1:-development}" case "$ENVIRONMENT" in production) export DB_HOST="prod-db.example.com" export DB_PORT="5432" export LOG_LEVEL="ERROR" export CACHE_ENABLED="true" ;; staging) export DB_HOST="staging-db.example.com" export DB_PORT="5432" export LOG_LEVEL="WARN" export CACHE_ENABLED="true" ;; development) export DB_HOST="localhost" export DB_PORT="5432" export LOG_LEVEL="DEBUG" export CACHE_ENABLED="false" ;; *) echo "Unknown environment: $ENVIRONMENT" echo "Valid options: production, staging, development" return 1 ;; esac echo "Loaded $ENVIRONMENT environment" echo " DB_HOST: $DB_HOST" echo " LOG_LEVEL: $LOG_LEVEL" EOF # Source with different arguments source ~/load_env.sh production echo "---" source ~/load_env.sh staging echo "---" source ~/load_env.sh development
Output:
Loaded production environment DB_HOST: prod-db.example.com LOG_LEVEL: ERROR --- Loaded staging environment DB_HOST: staging-db.example.com LOG_LEVEL: WARN --- Loaded development environment DB_HOST: localhost LOG_LEVEL: DEBUG
Note:

Arguments allow you to make sourced scripts more flexible. This pattern is commonly used for environment switching in development workflows.

Example 6

Conditional Sourcing and Error Handling

Check if a file exists before sourcing it and handle errors gracefully. This prevents your shell scripts from breaking if configuration files are missing.
# Safe sourcing with existence check if [ -f ~/.custom_config ]; then source ~/.custom_config echo "Custom configuration loaded" else echo "Custom configuration not found, using defaults" fi # Source with error handling if source ~/app_config.sh 2>/dev/null; then echo "Application config loaded successfully" else echo "Failed to load application config" exit 1 fi # Multiple configuration files with fallback for config in ~/.config/app/config.sh /etc/app/config.sh; do if [ -f "$config" ]; then source "$config" echo "Loaded configuration from: $config" break fi done # Function for safe sourcing safe_source() { local file="$1" if [ ! -f "$file" ]; then echo "Warning: File not found: $file" return 1 fi if source "$file"; then echo "Successfully sourced: $file" return 0 else echo "Error sourcing: $file" return 1 fi } # Use the function safe_source ~/my_config.sh
Output:
Custom configuration not found, using defaults Application config loaded successfully Loaded configuration from: /etc/app/config.sh Successfully sourced: ~/my_config.sh
Warning:

Always check if a file exists before sourcing it in scripts. A missing configuration file can cause the script to fail, and sourcing a non-existent file will throw an error that might exit your current shell.

Example 7

Source vs Execute - Understanding the Difference

Demonstrate the critical difference between sourcing a script and executing it. This example shows why understanding this distinction is essential for shell scripting.
# Create a test script cat > test_script.sh << 'EOF' #!/bin/bash # This script demonstrates source vs execute export TEST_VAR="Hello from script" cd /tmp echo "Inside script:" echo " TEST_VAR: $TEST_VAR" echo " PWD: $PWD" EOF chmod +x test_script.sh # Before running anything echo "Before running script:" echo " TEST_VAR: $TEST_VAR" echo " PWD: $PWD" echo "" # Method 1: Execute normally (creates subshell) echo "=== Executing normally (./test_script.sh) ===" ./test_script.sh echo "After normal execution:" echo " TEST_VAR: $TEST_VAR" # Empty! echo " PWD: $PWD" # Still in original directory echo "" # Method 2: Source the script (runs in current shell) echo "=== Sourcing (source test_script.sh) ===" source test_script.sh echo "After sourcing:" echo " TEST_VAR: $TEST_VAR" # Variable is set! echo " PWD: $PWD" # Directory changed! # Clean up cd - unset TEST_VAR
Output:
Before running script: TEST_VAR: PWD: /home/user === Executing normally (./test_script.sh) === Inside script: TEST_VAR: Hello from script PWD: /tmp After normal execution: TEST_VAR: PWD: /home/user === Sourcing (source test_script.sh) === Inside script: TEST_VAR: Hello from script PWD: /tmp After sourcing: TEST_VAR: Hello from script PWD: /tmp
Note:

This clearly shows that normal execution creates a subshell where changes are isolated, while source executes in the current shell where changes persist. This is fundamental to understanding when to use each approach.

Example 8

Interactive Configuration Menu

Create an interactive script that presents configuration options and sources the appropriate settings based on user choice. This demonstrates advanced sourcing techniques in a user-friendly way.
# Create project configuration system mkdir -p ~/project_configs # Create different config files cat > ~/project_configs/web_config.sh << 'EOF' export PROJECT_TYPE="web" export PORT="8080" export BUILD_CMD="npm run build" export START_CMD="npm start" alias proj-start='npm start' alias proj-build='npm run build' echo "Web project configuration loaded" EOF cat > ~/project_configs/python_config.sh << 'EOF' export PROJECT_TYPE="python" export VENV_PATH="./venv" export BUILD_CMD="python setup.py build" export START_CMD="python main.py" alias proj-start='source venv/bin/activate && python main.py' alias proj-build='python setup.py build' echo "Python project configuration loaded" EOF cat > ~/project_configs/java_config.sh << 'EOF' export PROJECT_TYPE="java" export MAVEN_OPTS="-Xmx2048m" export BUILD_CMD="mvn clean install" export START_CMD="java -jar target/app.jar" alias proj-start='java -jar target/app.jar' alias proj-build='mvn clean install' echo "Java project configuration loaded" EOF # Create interactive loader cat > ~/load_project.sh << 'EOF' #!/bin/bash echo "Select Project Configuration:" echo "1) Web (Node.js)" echo "2) Python" echo "3) Java" echo -n "Enter choice [1-3]: " read choice case $choice in 1) source ~/project_configs/web_config.sh ;; 2) source ~/project_configs/python_config.sh ;; 3) source ~/project_configs/java_config.sh ;; *) echo "Invalid choice" return 1 ;; esac echo "Project type: $PROJECT_TYPE" echo "Build command: $BUILD_CMD" echo "Start command: $START_CMD" EOF # Use it interactively source ~/load_project.sh
Output (User selects option 2):
Select Project Configuration: 1) Web (Node.js) 2) Python 3) Java Enter choice [1-3]: 2 Python project configuration loaded Project type: python Build command: python setup.py build Start command: python main.py # Now the aliases are available: $ proj-start # Would activate venv and run main.py
Note:

This pattern is useful for developers who work on multiple types of projects and need to quickly switch configurations. The sourced aliases and environment variables persist in the current shell.

Example 9

Source Within Scripts (Modular Configuration)

Use source within scripts to create modular, maintainable configurations. This approach separates concerns and makes complex deployment scripts easier to manage and update.
# Create modular configuration system mkdir -p ~/deploy_scripts/{base,database,webserver,monitoring} # Base configuration cat > ~/deploy_scripts/base/common.sh << 'EOF' #!/bin/bash LOG_DIR="/var/log/deployment" DEPLOY_USER="deployer" TIMESTAMP=$(date +%Y%m%d_%H%M%S) log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_DIR/deploy_$TIMESTAMP.log" } EOF # Database configuration cat > ~/deploy_scripts/database/postgres.sh << 'EOF' #!/bin/bash DB_HOST="localhost" DB_PORT="5432" DB_NAME="production" DB_BACKUP_DIR="/backups/postgres" backup_database() { log_message "Starting database backup" pg_dump -h $DB_HOST -p $DB_PORT $DB_NAME > "$DB_BACKUP_DIR/backup_$TIMESTAMP.sql" log_message "Database backup complete" } EOF # Web server configuration cat > ~/deploy_scripts/webserver/nginx.sh << 'EOF' #!/bin/bash NGINX_CONFIG="/etc/nginx/sites-available" WEB_ROOT="/var/www/html" restart_webserver() { log_message "Restarting nginx" sudo systemctl restart nginx log_message "Nginx restarted" } EOF # Main deployment script that sources everything cat > ~/deploy_scripts/deploy.sh << 'EOF' #!/bin/bash # Source all configuration modules SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/base/common.sh" source "$SCRIPT_DIR/database/postgres.sh" source "$SCRIPT_DIR/webserver/nginx.sh" log_message "=== Starting Deployment ===" log_message "Deployment user: $DEPLOY_USER" # Now we can use functions from all sourced files backup_database # ... deploy application code ... restart_webserver log_message "=== Deployment Complete ===" EOF chmod +x ~/deploy_scripts/deploy.sh # Run the deployment ~/deploy_scripts/deploy.sh
Output:
[2025-12-14 14:30:15] === Starting Deployment === [2025-12-14 14:30:15] Deployment user: deployer [2025-12-14 14:30:15] Starting database backup [2025-12-14 14:30:18] Database backup complete [2025-12-14 14:30:18] Restarting nginx [2025-12-14 14:30:20] Nginx restarted [2025-12-14 14:30:20] === Deployment Complete ===
Note:

This modular approach makes maintenance easier. Database configs go in one file, web server configs in another. When you need to update database settings, you only modify postgres.sh. The main script sources all modules to access their functions and variables.

Example 10

Advanced: Return vs Exit in Sourced Scripts

Understanding when to use 'return' versus 'exit' is critical for sourced scripts. Using 'exit' in a sourced script will close your current shell, while 'return' safely exits the sourced script. This example demonstrates safe practices.
# BAD: Script that uses exit (DO NOT SOURCE THIS) cat > ~/bad_script.sh << 'EOF' #!/bin/bash if [ ! -f "/some/required/file" ]; then echo "Required file not found" exit 1 # THIS WILL CLOSE YOUR SHELL IF SOURCED! fi EOF # GOOD: Script that uses return (safe to source) cat > ~/good_script.sh << 'EOF' #!/bin/bash if [ ! -f "/some/required/file" ]; then echo "Required file not found" return 1 # Safe - only exits the sourced script fi echo "File found, continuing..." EOF # Create a smart script that works both ways cat > ~/smart_script.sh << 'EOF' #!/bin/bash # Detect if being sourced or executed if [ "${BASH_SOURCE[0]}" = "${0}" ]; then # Being executed, not sourced - can use exit SOURCED=false else # Being sourced - must use return SOURCED=true fi # Function to exit appropriately smart_exit() { local exit_code=${1:-0} if [ "$SOURCED" = true ]; then return $exit_code else exit $exit_code fi } # Validation check if [ ! -d "/tmp" ]; then echo "Error: /tmp directory not found" smart_exit 1 fi # Set some variables export SMART_VAR="Loaded successfully" echo "Smart script loaded correctly" smart_exit 0 EOF chmod +x ~/smart_script.sh # Test it both ways echo "=== Test 1: Sourcing the smart script ===" source ~/smart_script.sh echo "Still here! SMART_VAR: $SMART_VAR" echo "" echo "=== Test 2: Executing the smart script ===" ./~/smart_script.sh echo "Still here! SMART_VAR: $SMART_VAR" # Will be empty echo "" # Demonstrate what happens with bad script echo "=== WARNING: Do NOT run this - it would close your shell ===" echo "# source ~/bad_script.sh # Would close your terminal!" echo "=== Safe to source ===" source ~/good_script.sh || echo "Returned with error code, but shell still open"
Output:
=== Test 1: Sourcing the smart script === Smart script loaded correctly Still here! SMART_VAR: Loaded successfully === Test 2: Executing the smart script === Smart script loaded correctly Still here! SMART_VAR: === WARNING: Do NOT run this - it would close your shell === # source ~/bad_script.sh # Would close your terminal! === Safe to source === Required file not found Returned with error code, but shell still open
Critical Warning:

NEVER use 'exit' in a script that will be sourced! It will close your current shell session. Always use 'return' instead. The smart_exit pattern shown here detects whether the script is sourced or executed and behaves appropriately.

Tips & Best Practices

Use . for POSIX Compatibility
The dot command (.) is POSIX-standard and works in all shells (sh, bash, zsh, etc.), while 'source' is bash-specific. For maximum portability, use the dot: . filename
Always Check File Existence First
Before sourcing a file in a script, check if it exists: [ -f file.sh ] && source file.sh. This prevents errors from missing configuration files and makes your scripts more robust.
Use return Not exit in Sourced Scripts
In scripts designed to be sourced, always use 'return' to exit early, never 'exit'. Using 'exit' will close the user's current shell session, which is almost never what you want.
Add Source Commands to .bashrc
For functions and configurations you want available in every shell, add source commands to your ~/.bashrc: source ~/my_functions.sh. This loads them automatically when you open a new terminal.
Use Absolute or Relative Paths
While source searches PATH, it's clearer to use explicit paths: source ./config.sh or source ~/config.sh. This makes it obvious which file you're sourcing and prevents unexpected behavior from PATH search order.
Detect if Script is Being Sourced
Use this test to detect sourcing: [ "${BASH_SOURCE[0]}" != "${0}" ]. This allows you to write scripts that work correctly whether sourced or executed directly.
Source Order Matters
When sourcing multiple files, order can be important. If config_b.sh depends on variables from config_a.sh, source config_a.sh first. Dependencies should always be sourced before dependent files.
Avoid Infinite Source Loops
Be careful not to create circular source dependencies (file A sources file B, which sources file A). Use guard variables if needed: [ -n "$GUARD_VAR" ] && return at the top of sourced files.
Document What Sourced Scripts Export
Add comments at the top of sourced scripts listing what they export/modify. This makes it clear what changes will persist in the user's shell: "# Exports: DB_HOST, DB_PORT, LOG_LEVEL"