virtualenv
Bash scripting
Python environment
shell script
command line

How to source virtualenv activate in a Bash script

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To activate a Python virtual environment inside a Bash script, use source /path/to/venv/bin/activate. The source command (or its shorthand .) executes the activate script in the current shell context, modifying PATH and PS1 so that subsequent commands use the virtual environment's Python and packages. A common mistake is running activate as a subprocess (without source), which activates the environment in a child shell that exits immediately, leaving the parent script unaffected.

Basic Usage

bash
1#!/bin/bash
2
3# Create and activate a virtual environment
4python3 -m venv myenv
5source myenv/bin/activate
6
7# Now python and pip point to the venv
8which python    # /path/to/myenv/bin/python
9pip install requests
10python my_script.py
11
12# Deactivate when done
13deactivate

The source command runs activate in the current shell process, so PATH changes persist for the rest of the script.

Why source Is Required

bash
1#!/bin/bash
2
3# WRONG: runs activate in a subshell — changes are lost
4./myenv/bin/activate        # Permissions error or no effect
5bash myenv/bin/activate     # Activates in child shell, then child exits
6
7# CORRECT: runs in current shell
8source myenv/bin/activate   # Changes PATH in current script
9. myenv/bin/activate        # Shorthand for source (POSIX compatible)

Without source, the script runs activate in a subprocess. When that subprocess exits, all environment changes (PATH, VIRTUAL_ENV, etc.) are discarded.

Using Absolute Paths

For scripts that may run from any directory, use absolute paths:

bash
1#!/bin/bash
2VENV_DIR="/home/deploy/app/venv"
3
4if [ -f "$VENV_DIR/bin/activate" ]; then
5    source "$VENV_DIR/bin/activate"
6    echo "Virtual environment activated: $VIRTUAL_ENV"
7else
8    echo "Error: Virtual environment not found at $VENV_DIR"
9    exit 1
10fi
11
12python manage.py migrate
13python manage.py runserver

Check that the activate script exists before sourcing to provide a clear error message.

Script-Relative Paths

Activate relative to the script's own location:

bash
1#!/bin/bash
2SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3VENV_DIR="$SCRIPT_DIR/venv"
4
5source "$VENV_DIR/bin/activate"
6python "$SCRIPT_DIR/app.py"
7deactivate

${BASH_SOURCE[0]} gives the path to the script itself, regardless of where it was called from.

CI/CD Pipeline Example

bash
1#!/bin/bash
2set -euo pipefail
3
4# Create venv if it doesn't exist
5if [ ! -d "venv" ]; then
6    python3 -m venv venv
7fi
8
9source venv/bin/activate
10
11pip install --upgrade pip
12pip install -r requirements.txt
13pytest tests/
14pylint src/
15
16deactivate

In CI pipelines, always use set -e to fail fast if any command errors.

Using with Cron Jobs

Cron jobs do not load shell profiles, so activate the virtual environment explicitly:

bash
# crontab entry
0 */6 * * * /bin/bash /home/deploy/scripts/run_task.sh >> /var/log/task.log 2>&1
bash
1#!/bin/bash
2# run_task.sh
3source /home/deploy/app/venv/bin/activate
4cd /home/deploy/app
5python process_data.py
6deactivate

Alternatively, skip activation entirely and call the venv's Python directly:

bash
# No activation needed — call the interpreter directly
/home/deploy/app/venv/bin/python /home/deploy/app/process_data.py

This is simpler for cron jobs and scripts that only run a single Python command.

POSIX sh Compatibility

The source command is a Bash builtin. For /bin/sh scripts, use . instead:

bash
1#!/bin/sh
2. /home/deploy/app/venv/bin/activate
3python my_script.py
4deactivate

The . command is POSIX-compliant and works in all Bourne-compatible shells.

Common Pitfalls

  • Running activate without source: Executing ./venv/bin/activate or bash venv/bin/activate runs it in a subprocess. The environment changes are lost when the subprocess exits. Always use source or . to run it in the current shell.
  • Hardcoding paths that differ between environments: A script with source /home/alice/venv/bin/activate breaks when run by a different user or on a different machine. Use script-relative paths with ${BASH_SOURCE[0]} or environment variables.
  • Forgetting that cron jobs have minimal PATH: Cron does not load .bashrc or .profile. The python3 and pip commands may not be found. Either activate the venv in the script or use the full path to the venv's Python binary.
  • Not checking if the virtual environment exists: If the venv directory is missing or corrupted, source venv/bin/activate fails silently or with a confusing error. Check [ -f venv/bin/activate ] before sourcing and exit with a clear message if it is missing.
  • Using source in a #!/bin/sh script: The source builtin is not available in POSIX sh. Use . venv/bin/activate (dot-space) instead, which is POSIX-compliant and works in all shells.

Summary

  • Use source venv/bin/activate (or . venv/bin/activate) to activate a virtualenv in a Bash script
  • source runs the script in the current shell; without it, changes are lost in a subprocess
  • Use absolute or script-relative paths for portability across environments
  • For cron jobs, either activate in the script or call the venv's Python directly (venv/bin/python)
  • Check that the activate file exists before sourcing to catch missing environments early
  • Use . instead of source for POSIX sh compatibility

Course illustration
Course illustration

All Rights Reserved.