Skip to content

Latest commit

 

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reenv

reenv is a lightweight Bash utility designed to track changes to the shell environment (variables, functions, aliases, completions, and Readline key bindings/variables) between two points in time and serialize those changes as sourceable Bash code.

This enables you to capture environment modifications (e.g., made within a subshell, a build script, or an installer) and replay them in your current shell or another shell session.

Table of Contents

TL;DR;

# 0. Source reenv
. /path/to/reenv.bash

# 1. Initialize baseline snapshot
reenv-base

# 2. Modify environment (variables, functions, aliases, completions, and Readline bindings)
export MY_VAR="hello"
my_func() { echo "world"; }
alias my_alias="echo hello world"

# 3. Capture changes to a file
reenv-cap > delta.sh

# ... Later, in another terminal...

# 4. Apply changes in another shell session
source delta.sh

Features

  • Tracks Variables, Functions, Aliases, Completions, and Readline Bindings: Detects new, modified, and deleted items (including Readline key bindings, macros, variables, and shell command bindings).
  • Preserves Export Status: Correctly tracks and reapplies export status (export / declare -x) for variables and functions.
  • Customizable Filter: Easily ignore specific variables or functions using a regular expression.

How it Works

reenv exposes two main commands:

  1. reenv-base: Captures the "before" snapshot (baseline) of all defined variables, functions, aliases, completions, and Readline bindings.
  2. reenv-cap: Captures the "after" snapshot, calculates the delta from the baseline, and prints sourceable Bash code representing the difference (e.g., adding/modifying environment variables, declaring functions, unsetting removed variables, and updating Readline bindings).

Requirements

  • Bash 4.2 or later (required for declare -g global declarations).
  • Python 3 (required for reenv-sort and reenv-comm implementations).

Installation

Simply clone the repository and source the script in your Bash shell or add it to your .bashrc / .bash_profile:

source /path/to/reenv.bash

What is NOT Captured

reenv only tracks shell and environment variables, functions, aliases, completions, and Readline bindings. It does not capture other aspects of the shell or system state, including:

  • System/Process State:
    • File system changes (creation, modification, or deletion of files/directories).
    • Background or foreground processes started during the session, and background job lists/job control state.
    • Active file descriptors, network connections, or pipe/stream redirections.
  • Shell Attributes, Settings & Limits:
    • The current working directory (e.g., calling cd changes directory, but the directory path changes are not captured as cd commands; PWD and OLDPWD are ignored by default).
    • Active shell options (e.g., flags set via shopt or set -o).
    • Shell resource limits (set via ulimit).
    • The file creation mask (umask).
    • Signal trap handlers (trap).
    • Terminal settings (stty).
  • Ignored Variables & Parameters:
    • Positional parameters ($1, $2, etc., and $#, $@, $*).
    • Special shell parameters (e.g., $IFS, $!, $?, $$-pid).
    • Read-only shell variables and internal Bash/environment variables (e.g., BASH_*, FUNCNAME, RANDOM, USER, SECONDS, etc., which are filtered out to prevent corruption during replay).

Usage Guide

1. Basic Environment Tracking

To track modifications in your active terminal:

# 1. Start the baseline snapshot
reenv-base

# 2. Modify the environment
export NEW_VAR="Hello World"
my_func() { echo "This is a function"; }
alias my_alias="echo 'This is an alias'"

# 3. Print the delta as sourceable bash code
reenv-cap

This will print:

#a:my_alias(alias)
alias my_alias='echo '\''This is an alias'\'''
#f:my_func()
my_func () 
{ 
    echo "This is a function"
}
#v:NEW_VAR
declare -g -x NEW_VAR="Hello World"

2. Capturing Subshell Changes

If you run setup scripts or installer routines inside a subshell (or within a script) and want to load their environment changes back into your main shell:

# 1. Capture baseline in the main shell
reenv-base

# 2. Perform work in a subshell, dumping the delta to a file
(
    export DEBIAN_FRONTEND=noninteractive
    export PATH="/opt/my-app/bin:$PATH"
    
    # Capture modifications made inside this subshell
    reenv-cap > /tmp/env_delta.sh
)

# 3. Replay changes in the parent shell
source /tmp/env_delta.sh

3. Exporting and Applying Aliases and Functions

Since reenv-cap generates standard shell declarations, any aliases and exported/unexported functions will be properly re-applied:

reenv-base

# Add an exported function
my_exported_func() {
    echo "Exported function!"
}
export -f my_exported_func

# Delete an existing variable
unset SOME_OLD_VAR

# Capture the delta
reenv-cap > /tmp/delta.sh

Applying /tmp/delta.sh in another shell session will unset SOME_OLD_VAR, define my_exported_func, and call export -f my_exported_func to ensure it is available to child processes.

Configuration

reenv can be customized using the following environment variables:

Excluding Items (REENV_SKIP)

By default, reenv ignores internal Bash variables and read-only shell attributes (e.g., BASH_*, FUNCNAME, RANDOM, USER, PWD, COLUMNS, etc.).

If you want to ignore additional variables or functions, define REENV_SKIP with a regular expression pattern matching their names:

# Ignore any variables starting with "TEMP_" or containing "SECRET"
export REENV_SKIP="(^TEMP_|_SECRET_)"

# Take baseline
reenv-base

Advanced Usage

By default, reenv writes environment snapshots to temporary files. If you want to use specific files instead of the default temporary files, you can specify custom file paths using the -b and -f options.

Specifying Custom Base/Cap/Output Files (-b, -f, -o)

  • In reenv-base: Use -b FILENAME to capture the baseline snapshot. This will save the baseline state into FILENAME.sh and the unset definitions into FILENAME-clear.sh.

    reenv-base -b /tmp/my_baseline
  • In reenv-cap:

    • Use -b FILENAME to load the baseline snapshot from FILENAME.sh and FILENAME-clear.sh instead of the default temporary files.
    • Use -f FILENAME to save the "after" state snapshot into FILENAME.sh and FILENAME-clear.sh.
    • Use -o FILENAME to write the generated environment delta directly to FILENAME instead of printing to standard output.

    If -o is not specified, reenv-cap prints the environment delta to standard output:

    # Calculate delta comparing custom baseline and custom current snapshot, and redirect stdout to a file
    reenv-cap -b /tmp/my_baseline -f /tmp/my_current > /tmp/delta.sh

Suppressing Status Messages (-q)

You can pass the -q option to either reenv-base or reenv-cap to suppress status messages printed to stderr:

# Capture baseline quietly
reenv-base -q

# Capture delta quietly
reenv-cap -q > delta.sh

Limitations

reenv tracks entire environment states and variables rather than identifying changes within individual variables.

  • No Internal/Incremental Deltas (e.g., PATH modifications): If a variable's value is modified (for example, appending a path to PATH using export PATH="$PATH:/new/path"), reenv captures and re-emits the entire new value of PATH (e.g., declare -x PATH="...:/new/path"). It does not detect the incremental change or output self-referential definitions like export PATH="$PATH:/new/path".

  • Local Variables Applied as Global: If a variable is local to an active shell function (i.e., declared with local), reenv captures its value at the time of tracking. However, when the generated delta script is replayed, all captured variables are re-applied as global variables (using declare -g).

Running Tests

reenv comes with a comprehensive test suite in reenv.bash.test. To run the tests, execute the script directly:

./reenv.bash.test

Potentially Supportable Shell Attributes

The following shell attributes are currently listed under "What is NOT Captured" but are technically viable candidates for future support:

1. Shell Options (shopt and set -o / set +o)

  • Save/Restore:
    • Save: Query active options using shopt -p and standard shell flags using set +o.
    • Restore: Emit changed options directly (e.g., shopt -s autocd or set -o history).
  • Caveats: Some shell options might change behavior in ways that disrupt the sourced script execution itself (e.g., errexit or nounset), so care must be taken when re-applying them.

2. Signal Trap Handlers (trap)

  • Save/Restore:
    • Save: Query active signal traps via trap -p.
    • Restore: Reset removed traps using trap - <signal> and declare new/modified ones using trap -- '<command>' <signal>.
  • Caveats: Signal traps are bound to the process, so some traps might not make sense or could behave unexpectedly when replayed in a different shell session with different process IDs.

3. File Creation Mask (umask)

  • Save/Restore:
    • Save: Query using umask -p.
    • Restore: Re-apply using umask <value> if it changes.
  • Caveats: None.

4. Shell Resource Limits (ulimit)

  • Save/Restore:
    • Save: Parse option flags and limits from ulimit -a (soft) and ulimit -Ha (hard).
    • Restore: Apply changes via ulimit -S <flag> <value> or ulimit -H <flag> <value>.
  • Caveats: Non-root users cannot raise hard limits (only lower them) and cannot raise soft limits beyond the current shell's hard limits. To prevent replay scripts from failing, restore commands should be guarded (e.g., appending 2>/dev/null || true).

5. Current Working Directory (cd / PWD)

  • Save/Restore:
    • Save: Query current path using pwd.
    • Restore: Emit cd '<path>' if changed.
  • Caveats: Changing the directory upon replay might be undesirable or confusing if the user only wanted to capture environment variables/aliases and not change their current location.

License

This project is licensed under the MIT License.

About

Capture shell environment changes (variables, exports, functions) as sourceable bash code to replay them in another shell

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages