Table of Contents
📖 2 minutes read
I was setting up Git hooks to auto-sync my project workspace on exit, but I couldn’t see any output. The hook ran silently—no success messages, no errors, nothing. I had no idea if it was even working.
The problem? Hook scripts inherit their parent’s stdout/stderr, but they often run in contexts where those streams are redirected to /dev/null. So even if you echo messages, you’ll never see them.
The Solution: Redirect stderr to stdout, Then Format
To make hook output visible, you need to:
- Redirect stderr to stdout (
2>&1) - Pipe through
sedto add indentation - Redirect back to stderr (
>&2) so it appears in the terminal
Here’s the pattern:
#!/bin/bash
# Run your command and make output visible
my-sync-script.sh 2>&1 | sed 's/^/ /' >&2
What’s Happening Here?
2>&1— Merge stderr into stdout (captures all output)| sed 's/^/ /'— Add 2 spaces to the start of each line (formatting)>&2— Send the formatted output to stderr (visible in terminal)
Example: Auto-Sync on Git Exit
I used this pattern in a boot script that syncs project files from Google Drive before running:
#!/bin/bash
# ~/.local/bin/sync-workspace.sh
echo "🔄 Syncing workspace from Google Drive..."
rclone sync gdrive:workspace /local/workspace \
--fast-list \
--transfers 8 \
2>&1 | sed 's/^/ /' >&2
echo "✅ Workspace synced"
Now when the script runs, I see:
🔄 Syncing workspace from Google Drive...
Transferred: 1.2 MiB / 1.2 MiB, 100%
Checks: 47 / 47, 100%
✅ Workspace synced
When to Use This
- Git hooks (pre-commit, post-checkout, etc.)
- Boot scripts that run on system startup
- Cron jobs where you want output logged
- Any background process where visibility helps debugging
Without this pattern, your hooks run silently. With it, you get clear feedback—success messages, error details, everything.
Leave a Reply