Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@rgov
Created May 5, 2019 19:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rgov/a1f9c8de16f8c35cefa492b18d3c0178 to your computer and use it in GitHub Desktop.
Save rgov/a1f9c8de16f8c35cefa492b18d3c0178 to your computer and use it in GitHub Desktop.
#!/bin/sh
TMPDIR="$(mktemp -d)"
# Capture the default shell options, before we enter POSIX mode
set +o | sort > "$TMPDIR/shellopts.old"
echo "set -$-" >> "$TMPDIR/shellopts.old"
set -o posix
# Capture global variables
set | sort > "$TMPDIR/globals.old"
# Capture function names and definitions
declare -F | sort > "$TMPDIR/funcnames.old"
mkdir "$TMPDIR/funcs.old"
while read LINE; do
FUNC_NAME=$(echo "$LINE" | cut -d ' ' -f 3)
declare -f "$FUNC_NAME" > "$TMPDIR/funcs.old/$FUNC_NAME"
done < "$TMPDIR/funcnames.old"
# Reset shell options and source the file
(
source "$TMPDIR/shellopts.old";
source "$1";
# Capture shell options
set +o | sort > "$TMPDIR/shellopts.new"
echo "set -$-" >> "$TMPDIR/shellopts.new"
# Capture global variables
set | sort > "$TMPDIR/globals.new"
# Capture function names and definitions
declare -F | sort > "$TMPDIR/funcnames.new"
mkdir "$TMPDIR/funcs.new"
while read LINE; do
FUNC_NAME=$(echo "$LINE" | cut -d ' ' -f 3)
declare -f "$FUNC_NAME" > "$TMPDIR/funcs.new/$FUNC_NAME"
done < "$TMPDIR/funcnames.new"
)
# Output the shell options
cat "$TMPDIR/shellopts.new"
# Diff the global variables
diff \
--new-line-format='+%L' \
--old-line-format='-%L' \
--unchanged-line-format=' %L' \
"$TMPDIR/globals.old" \
"$TMPDIR/globals.new" \
> "$TMPDIR/globals.diff"
while read LINE; do
FIRST=$(echo "$LINE" | cut -c 1)
REST=$(echo "$LINE" | cut -c 2-)
VARNAME=$(echo "$REST" | cut -d = -f 1)
case "$FIRST" in
+) echo "$REST" ;;
-) echo "unset $VARNAME" ;;
esac
done < "$TMPDIR/globals.diff"
# Diff the functions
diff \
--new-line-format='+%L' \
--old-line-format='-%L' \
--unchanged-line-format=' %L' \
"$TMPDIR/funcnames.old" \
"$TMPDIR/funcnames.new" \
> "$TMPDIR/funcnames.diff"
while read LINE; do
FIRST=$(echo "$LINE" | cut -c 1)
REST=$(echo "$LINE" | cut -c 2-)
FUNC_NAME=$(echo "$REST" | cut -d ' ' -f 3)
case "$FIRST" in
+) cat "$TMPDIR/funcs.new/$FUNC_NAME" ;;
-) echo "unset -f $FUNC_NAME" ;;
*)
if ! diff "$TMPDIR/funcs.old/$FUNC_NAME" "$TMPDIR/funcs.new/$FUNC_NAME" &>/dev/null; then
cat "$TMPDIR/funcs.new/$FUNC_NAME"
fi
;;
esac
done < "$TMPDIR/funcnames.diff"
# Clean up temporary files
rm -Rf "$TMPDIR"
@rgov
Copy link
Author

rgov commented May 5, 2019

This garish script is hopefully a POSIX-compliant version of diffing the output of Bash's set before and after sourceing a shell script. The idea was to capture how loading virtual environment affects the shell session.

It captures shell options, global variables, and function definitions.

Future work:

  • Handle aliases
  • Handle read-only variables like Bash's SHELLOPTS
  • Do not unset a modified variable, just change it
  • Exclude shell options that did not change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment