Bash Script Environment Variables Not Persisting After Execution: Solaris 11 Export Issue


2 views

When working with bash scripts on Solaris 11, you might encounter a situation where environment variables set within a script don't persist after the script finishes execution. This occurs despite using the export command correctly.

Here's a fundamental Unix principle at play:

#!/usr/bin/bash
TEST="value_to_persist"
export TEST

The script above runs in its own subshell, and any environment changes are confined to that subshell. When the script terminates, the subshell and its environment are destroyed.

1. Sourcing the Script

Instead of executing the script, source it:

source ./script.sh
# or
. ./script.sh

2. Using Environment Files

Create an environment file and load it:

# In script.sh
echo "export TEST=persisted_value" > /tmp/env_vars

# In parent shell
source /tmp/env_vars

3. Command Substitution

For simple variable assignments:

eval $(echo "TEST=persisted_value")

Solaris 11's default shell might be different from what you expect. Always verify:

# Check your current shell
echo $SHELL

# Explicitly use bash
#!/usr/bin/bash

Add these checks to your script:

#!/usr/bin/bash
echo "Parent PID: $PPID"
echo "Current PID: $$"
export TEST=debug_value
env | grep TEST

When working with bash scripts, it's crucial to understand that child processes (including scripts) cannot modify their parent process's environment. This is by Unix design - each process maintains its own environment space. Here's what's happening in your example:

# Parent shell
$ TEST="parent_value"  # Sets variable in parent shell
$ ./test.sh            # Child process starts
  # Inside test.sh:
  TEST="child_value"   # Only modifies child's environment
  exit                 # Child terminates, environment discarded
# Back in parent shell
$ echo $TEST           # Still shows "parent_value"

Let's examine a more comprehensive test case showing the scope boundaries:

#!/bin/bash
# script_scope_demo.sh

# Initial state
echo "Script start - TEST value: ${TEST:-unset}"

# Local assignment
TEST="script_local"
echo "After local assignment: $TEST"

# Export attempt
export TEST="script_exported"
echo "After export: $TEST"

# Function call demonstrating same behavior
nested_function() {
    TEST="function_value"
    echo "Inside function: $TEST"
}
nested_function
echo "After function: $TEST"

# End of script - all changes disappear

If you need to modify the parent shell's environment, consider these approaches:

# Method 1: Sourcing the script
$ source ./test.sh    # or equivalently: . ./test.sh
# Variables will persist because script runs in current shell

# Method 2: Explicit evaluation
$ eval "$(./env_generator.sh)"  
# Where env_generator.sh outputs 'export' commands

# Method 3: Temporary environment file
#!/bin/bash
# set_env.sh
echo "export TEST=$(date +%s)" > /tmp/myenv
# Then in parent shell:
$ source /tmp/myenv

For complex cases where you need to maintain environment changes across multiple script invocations:

#!/bin/bash
# env_manager.sh

# Preserve existing environment
ENV_FILE="${ENV_FILE:-/tmp/current_env}"
trap 'export -p > "$ENV_FILE"' EXIT

# Your script logic here
if [[ -f "$ENV_FILE" ]]; then
    source "$ENV_FILE"
fi

# Make modifications
export LAST_RUN="$(date)"
export COUNTER=$(( ${COUNTER:-0} + 1 ))

Use these commands to inspect environment behavior:

# Show all exported variables
$ export -p

# Check if specific variable is exported
$ declare -p TEST

# Compare parent and child environments
$ env > parent_env.txt
$ bash -c 'env' > child_env.txt
$ diff parent_env.txt child_env.txt