How to Edit Files Without Vim or Nano Using Sed (Production Survival Guide)
It was 11:23 PM. I was debugging self-hosted PostgreSQL HA setup and vim wasn’t available in the container. This is the story of how sed…
How to Edit Files Without Vim or Nano Using Sed (Production Survival Guide)
It was 11:23 PM. I was debugging self-hosted PostgreSQL HA setup and vim wasn’t available in the container. This is the story of how sed become my go-to tool for quick fixes in production environments.

It was around 11:30 PM on a weekday. I was debugging an issue with our company’s PostgreSQL HA setup running in Docker containers. The error logs pointed to a misconfigured pg_hba.conf, and I needed to add a new IP to the authentication rules.
I SSH’d into the container, ran which vim… nothing. which nano… nothing. I sat there for a second, heart rate rising, and then I remembered: sed is always there.
This is the story of how I stopped fearing sed and started using it for every quick fix in production.
The Problem: Minimal Images Don’t Have Editors
Production container images are built for size, not developer convenience. Alpine, Debian slim — they ship with the essentials, not vim or nano.
# Check what you actually have inside a container
docker exec postgres-primary which vim
# (nothing)
docker exec postgres-primary which nano
# (nothing)
docker exec postgres-container which sed
/usr/bin/sed
This isn’t a bug. It’s a deliberate choice. But when you need to make a quick change at 11 PM while the team is waiting, you work with what you have.
What sed Actually Does
sed works like a conveyor belt — it reads each line, applies your instruction, and moves on. No GUI, no interactive mode, just stream processing.
sed 's/old/new/' file
# Reads line 1 → applies s/old/new/ → prints result
# Reads line 2 → applies s/old/new/ → prints result
# ...continues until end
Once I understood this, everything clicked. sed isn’t a text editor — it’s a line transformer. And that’s exactly what you need in production at 11 PM.
The Commands I Actually Use
After months of emergency debugging at work, I’ve narrowed it down to five commands I use repeatedly. These handle 95% of what I need.
- Substitute —
s/old/new
Find and replace text on matching lines:
# Change max_connections from 100 to 500
sed '/max_connections/s/100/500/' postgresql.conf
# Make it global (all occurrences per line)
sed 's/100/500/g' postgresql.conf
# Print only what changed (dry-run)
sed -n 's/100/500/p' postgresql.conf
The pattern I use most: sed ‘/PATTERN/s/old/new/’ file
- First, find lines containing PATTERN
- Then, replace old with new on those lines only
- Delete —
d
Remove lines by pattern, number, or range:
# Delete empty lines
sed '/^$/d' file
# Delete lines containing "debug"
sed '/debug/d' file
# Delete lines NOT matching (keep only matches)
sed '/ERROR/!d' file
# Delete specific line number
sed '42d' file
# Delete a range
sed '10,20d' file
- Insert Before —
i\
Add a line before matching lines:
# Insert a comment before max_connections
sed '/max_connections/i\# Modified by SRE' postgresql.conf
# Insert at specific line number
sed '5i\# Configuration header' file
- Append After —
a\
Add a line after matching lines:
# Add new IP to pg_hba.conf after localhost entry
sed '/^host.*all.*all.*127.0.0.1\/32/a host all all 10.20.30.40/32 md5' pg_hba.conf
# Append after line matching listen_addresses
sed '/listen_addresses/a\port = 5433' postgresql.conf
⚠️ Watch out: Unlike s/ which edits text, c\ replaces the entire line. Use pattern matching to be safe.
Targeting Specific Lines: Address Types
Without an address, sed applies to ALL lines. Here’s how I target exactly what I need:
# Line number only (line 42)
sed '42s/old/new/' file
# Line range (lines 10 to 20)
sed '10,20s/old/new/' file
# Pattern match (lines with "max_connections")
sed '/max_connections/s/old/new/' file
# From line 50 to end of file
sed '50,$s/old/new/' file
# Range between patterns
sed '/^# Authentication/,/^$/s/old/new/' file
In-Place Editing: The -i Flag
By Default, sed prints to the screen and leaves the file unchanged. Use -i to modify the file directly:
# ⚠️ DANGEROUS - no backup
sed -i 's/old/new/' file
# ✅ RECOMMENDED - creates .bak backup
sed -i.bak 's/old/new/' file
# If things go wrong, rollback instantly
mv file.bak file
This is the first thing I tell anyone: Always use -i.bak. Never plain -i. The backup is your safety net.
Multiple Changes at Once
Real configs need multiple fixes. Chain commands with -e:
sed -i.bak \
-e 's/max_connections = 100/max_connections = 500/' \
-e '/listen_addresses/a\port = 5433' \
-e '/WARNING/s/^/# /' \
file.conf
Special Characters: The Trap That Cost Me an Hour
Dots (.) match ANY character in sed patterns. For literal dots, escape them:
# Wrong: dots in IP match anything
sed 's/10.0.0.1/192.168.1.1/' pg_hba.conf
# Matches "10X0Y0Z1" too!
# Correct: escaped dots match literally
sed 's/10\.0\.0\.1/192.168.1.1/' pg_hba.conf
When patterns contain /, use alternate delimiters:
# Instead of escaping every /
sed 's|/etc/postgresql|/opt/postgresql|' file
# Or use | (pipe)
sed 's|path/to/file|new/path|' file
The First-Occurrence Trick: 0,/pattern/
By default, sed changes ALL matching lines. But sometimes you only want the first:
# Change only the first "trust" to "md5"
sed '0,/trust/s/trust/md5/' pg_hba.conf
The 0,/pattern/ syntax means: “Find the first line matching PATTERN, apply the substitution, then stop.”
Why My Changes Didn’t Persist After Restart (The Story)
This cost me an hour of debugging at work one night:
docker exec postgres sed -i 's/max_connections = 100/max_connections = 500/' /var/lib/postgresql/data/postgresql.conf
docker restart postgres
# Check config... still 100?!
The problem: Many Docker images regenerate their configs at startup from environment variables. My sed change was there, but the startup script overwrote it.
The fix depends on your situation:
- Use environment variables (if the image supports them):
environment:
POSTGRES_MAX_CONNECTIONS: 500
- Mount custom config from host:
volumes:
- ./custom.conf:/etc/postgresql/custom.conf:ro
- Use init scripts for one-time setup.
Knowing this saved me from many hours of “why isn’t this working?”
Reloading Config Without Restart
Some PostgreSQL settings can be reloaded without restarting:
# Reload PostgreSQL config
docker exec postgres psql -U postgres -c "SELECT pg_reload_conf();"
Settings that reload without a restart: log_line_prefix, log_statement, listen_addresses.
Settings that require a restart: max_connections, shared_buffers, port, wal_level.
My Go-To Patterns
After months of emergency debugging at work, these are the commands I keep in my muscle memory:
# Comment out a line
sed '/PATTERN/s/^/# /' file
# Uncomment a line (remove leading #)
sed '/^# PATTERN/s/^# //' file
# Change a specific value
sed "s/^PATTERN = .*/PATTERN = NEW_VALUE/" file
# Add new line after pattern
sed '/PATTERN/a\NEW_LINE' file
# Delete lines matching pattern
sed '/PATTERN/d' file
# Replace entire line
sed '/PATTERN/c\REPLACEMENT' file
Safety Checklist
Before editing any production file:
- Always backup:
sed -i.bak ‘...’ file - Dry-run first:
sed -n ‘s/old/new/p’ file(see what changes) - Verify:
grep “new_value” file - Rollback if needed:
mv file.bak file
When sed is Not the Answer
| Use Case | Better Tool |
| ---------------------------- | ----------- |
| JSON files | `jq` |
| YAML files | `yq` |
| Complex multi-line | `perl` |
| Structured config management | `ansible` |
For quick emergency fixes inside containers, sed is perfect. For repeatable infrastructure, use proper tooling like Ansible.
The Bottom Line
Every developer and SRE should know sed. It’s available on virtually every Unix system, works without text editors, and handles the quick fixes you need when you’re debugging production at 11 PM.
The five commands I use most: s/ (substitute), d (delete), i\ (insert before), a\ (append after), c\ (change). That’s 95% of what I need.
Next time you’re stuck inside a container with no editors available, remember: sed is your friend.
메타데이터
- post_id
- 7345a25e2d5d
- slug
- sed-for-emergency-debugging-when-vim-and-nano-are-not-an-option-7345a25e2d5d
- url
- https://medium.com/@2ssk/sed-for-emergency-debugging-when-vim-and-nano-are-not-an-option-7345a25e2d5d
- canonical_url
- https://medium.com/@2ssk/sed-for-emergency-debugging-when-vim-and-nano-are-not-an-option-7345a25e2d5d
- author_url
- https://medium.com/@2ssk
- status
- ok
- fetched_at
- 2026-06-09 15:37:30