In Bash scripting, subshells are created using parentheses ()
and are often used for parallel execution or simple scoping. But there’s another use case that can greatly enhance script hygiene and security: creating isolated execution environments for sensitive operations. Think of it as running your logic in an incognito tab: temporary, scoped, and self-cleaning.
Let’s explore this concept with a real-world use case: provisioning a Google Cloud VM instance using temporary authentication in a throwaway environment.
💡 What is an Incognito Shell?
An Incognito Shell is a term (coined for clarity here) describing the use of a Bash subshell to temporarily:
- Export environment variables
- Authenticate using credentials
- Perform a sequence of commands
- Automatically clean up afterwards
Unlike the main shell, the subshell doesn’t persist variables or config beyond its scope, making it ideal for handling credentials and other sensitive state.
📄 Example Use Case: GCE Instance Creation Script
Consider the following shell script that provisions a Google Compute Engine (GCE) instance using a service account key. Credentials are scoped inside a subshell, preventing them from leaking into the outer environment.
#!/bin/bash
set -euxo pipefail
# Constants
INSTANCE_NAME="instance-1"
PROJECT_ID="my-project-id"
ZONE="asia-south1-a"
MACHINE_TYPE="e2-micro"
HARDDISK_SIZE_GB=10
KEY_FILE="$(realpath ../docker_k/dockerbuild.json)"
# Begin Incognito Shell
(
TEMP_DIR=$(mktemp -d)
export CLOUDSDK_CONFIG="$TEMP_DIR"
# Authenticate using temporary config dir
gcloud auth activate-service-account --key-file="${KEY_FILE}" || {
echo "❌ Failed to authenticate with the provided key file."
exit 1
}
gcloud config set project "${PROJECT_ID}"
# Check for existing instance
if gcloud compute instances describe "${INSTANCE_NAME}" \
--project="${PROJECT_ID}" \
--zone="${ZONE}" >/dev/null 2>&1; then
echo "❌ Instance '${INSTANCE_NAME}' already exists."
exit 1
else
echo "✅ Instance '${INSTANCE_NAME}' does not exist. Proceeding."
fi
# Create instance
gcloud compute instances create "${INSTANCE_NAME}" \
--project="${PROJECT_ID}" \
--zone="${ZONE}" \
--machine-type="${MACHINE_TYPE}" \
--network-interface=network-tier=PREMIUM,stack-type=IPV4_ONLY,subnet=default \
--can-ip-forward \
--maintenance-policy=MIGRATE \
--provisioning-model=STANDARD \
--service-account=1070710XXXXXX-compute@developer.gserviceaccount.com \
--scopes=https://www.googleapis.com/auth/devstorage.read_only,\
https://www.googleapis.com/auth/logging.write,\
https://www.googleapis.com/auth/monitoring.write,\
https://www.googleapis.com/auth/service.management.readonly,\
https://www.googleapis.com/auth/servicecontrol,\
https://www.googleapis.com/auth/trace.append \
--tags=http-server,https-server \
--create-disk=auto-delete=yes,boot=yes,device-name=${INSTANCE_NAME},\
image=projects/debian-cloud/global/images/debian-12-bookworm-v20250709,\
mode=rw,size=${HARDDISK_SIZE_GB},type=pd-balanced \
--no-shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring \
--labels=goog-ec-src=vm_add-gcloud \
--reservation-affinity=any
# Subshell exits here, temp config and auth are discarded
)
🧼 Why Use a Subshell?
-
Credential Isolation: Sensitive variables (e.g.,
CLOUDSDK_CONFIG
) and temp auth tokens don’t leak into your shell history or environment. -
Automatic Cleanup: The temporary directory (
mktemp -d
) vanishes with the subshell. No trap needed. -
Safe Failures: If something fails inside, it doesn’t pollute your outer environment. This makes debugging and rerunning safer.
-
Reusability: You can easily copy/paste or reuse the subshell logic in other scripts without worrying about side effects.
🔄 Alternative Without Subshell
You could manually clean up, but it’s messier:
export CLOUDSDK_CONFIG=$(mktemp -d)
# ...
# Then remember to clean it up
rm -rf "$CLOUDSDK_CONFIG"
unset CLOUDSDK_CONFIG
This approach is error-prone and easy to forget, especially in larger scripts.
🧠 Pro Tip: Nesting Incognito Shells
You can nest subshells for nested scopes. For instance, authenticating with one service inside a broader scoped environment (e.g., Terraform, Docker, etc.).
(
export AWS_CONFIG_FILE="$(mktemp)"
(
export CLOUDSDK_CONFIG="$(mktemp -d)"
# Do GCP stuff here
)
# Do AWS stuff here
)
✅ Conclusion
The humble Bash subshell offers a lightweight, elegant way to sandbox parts of your script, especially when dealing with temporary credentials or environment state. By thinking of it as an “Incognito Shell”, you can write cleaner, safer, and more maintainable scripts.