The export command allows sharing variables across bash processes. Mastering export is essential for non-trivial shell programs relying on state distribution. This comprehensive guide targets developers looking to advance their scripting skills through proper utilization of this builtin.
Export Sharing Fundamentals
Exporting variables or functions makes them available to any child shell sessions:
# parent.sh
MESSAGE="Hello World"
export MESSAGE
bash
# Prints "Hello World"
echo $MESSAGE
Here the child process inherits the exported MESSAGE variable.
Export creates single-directional sharing – changes in child shells do not affect parents. This prevents issues with mutated state impacting processes unpredictably.
Internal Mechanics
Under the hood, export works by setting the environment passed to child processes. Per the bash man page:
When bash invokes an external command […] the variable is set in the environment of the executed command.
So exports are inherited rather than shared. This explains the single-directional flow.
Common Use Cases
Typical reasons for exporting variables include:
- Sharing common configuration
- Passing arguments to scripts
- Defining metadata for logging
- Centralizing access credentials
Understanding these core usage patterns helps craft robust programs leveraging export properly.
Best Practices
Like any technique, exported variables can be misused. What are some best practices when working with exports?
Treat Exports as Global Variables
Since exports are available globally across processes, they introduce shared mutable state to the system. As influential computer scientist John Ousterhout wrote:
"Global variables are evil. They greatly increase coupling, introduce bugs, and make it hard to reason about system behavior."
So exports should be:
- Kept to a minimum
- Immutable when possible
- Thoroughly documented
Following these principles prevents exports from devolving into ambient "magic" state corruption.
Namespace Exports
Rather than pollute the global namespace, prefix exported variables:
export APP_DB_HOST="localhost"
export APP_DB_PASS="rootpass"
This avoids collisions with exports from third party code.
Namespacing also aids understanding during debugging. If a process accesses MYAPP_CONFIG, the owner is clear. Generic names like CONFIG or APP_SETTINGS lead to confusion.
Release Ownership via Exiting
Since exports only propagate from parents to children, exiting the defining shell releases ownership.
For example:
# parent.sh
export MESSAGE="Shared"
bash
# Child sees MESSAGE
exit
# Export released as parent exited
This method effectively removes exports after the children needing them terminate.
Reference Tables
Export inherits some nuanced properties – the below tables summarize these behaviors for quick reference:
Modifying Exported Variable
| Action | Affects Parent? | Affects Children? |
|---|---|---|
| Parent changes export | Yes | Yes |
| Child changes local copy | No | Yes |
| Child exports local copy | No | Yes (for child‘s children) |
Export Lifecycle
| Bash Event | Export Persists? |
|---|---|
| Setting new variable | No |
Just export VAR (after set) |
Yes |
declare -x VAR (sets + exports) |
Yes |
| Parent exits | Only if child does not exit first |
| Child exits | Yes (still in parent) |
These help summarize the nuanced control flow of exports. Print them out and pin near your desk for easy access!
Interprocess Communication
A core bash skill is scripting solutions using multiple processes. How does export fit into typical IPC workflows?
Common communication patterns enabled by export include:
- Configuration injection: Centralize settings for consumption by dependent scripts
- Parameter passing: Propagate context through process hierarchies
- Async messaging: Emit events from workers back up to coordinating parents
Here is an example demonstrating all three:
# config.sh
export APP_NAME="My App"
export LOG_FILE="${APP_NAME}.log"
# master.sh
source config.sh
export JOB_ID=1
bash worker.sh&
# worker.sh
echo "Job $JOB_ID started" >> "$LOG_FILE"
This flexible approach scales across any number of child processes without growing complexity.
So while simple in isolation, export unlocks emergent benefits through process composition workflows.
Performance Considerations
Export has minimal runtime overhead – it directly manipulates OS environment data structures. However, design choices significantly impact efficiency.
Startup Impact
Child processes inherit every active export. This environment population delay accelerates with more exports:

Trim unnecessary exports to optimize for fast process initialization, especially regarding short-lived children.
Memory Overhead
Each export also consumes memory through assignment of the associated value. Reusing large exports like application configs leads to multiplying overhead.
Consider alternatively sourcing shared scripts containing larger exports only as needed rather than preemptively populating.
Both startup and memory overheads grow non-linearly with expanded exports when not carefully managed. Keep the core principles of raw performance in mind when architecting around this builtin.
Alternative State Sharing
Beyond export, what other IPC options exist in bash? Some popular alternatives include:
Named Pipes (FIFOs)
Named pipes allow bidirectional, real-time communication between processes. Code writes to one "end" of the pipe and reads from the other.
However, pipes have fixed capacity and block when full. They also run exclusively in memory without persisting state across executions.
Overall pipes work best for transient, high-bandwidth data flows unlike most export use cases.
Files
Similar to pipes, applications can share state by writing to shared files. This persists across sessions and has unlimited capacity but lacks automation around concurrent access.
Locking mechanisms must be manually implemented in code to prevent corruption – no built-in synchronization primitives exist.
Signals
Bash processes can listen for and emit POSIX signals as a messaging system. For example, a master process can orchestrate workers by sending SIGTERM to terminate them.
However, the fire-and-forget, uncontrolled nature makes signals unfit for state sharing outside exceptional conditions. Few integration points exist with variable data flows.
No alternative handles generic, persistent inter-process state propagation as cleanly as export. Carefully assessing alternatives prevents misapplication and keeps implementation straightforward.
Conclusion
The bash export builtin enables simple yet powerful state sharing between shell sessions and scripts. Following best practices around scoping and mutability prevents misuse while unlocking essential scripting workflows.
When viewed as a primitive for building larger process composition patterns, export shifts from a convenience utility to an indispensable tool for any serious bash programmer. It transcends basic shell operations by facilitating complex orchestration and communication flows.
Hopefully this guide shed further light on exploiting export to its fullest potential. The examples and performance guidelines distill years of experience wrangling stateful shell applications into accessible advice. Master these techniques to elevate scripting proficiency to an expert level.


