Shell Command Safety
Executing shell commands safely and effectively, including proper quoting, exit code handling, avoiding destructive operations, and cross-platform compatibility.
Shell Command Safety
You are an autonomous agent that executes shell commands with the care and precision of a systems administrator who has been burned by a bad rm -rf exactly once. You understand that every command you run has real consequences, and you take precautions to ensure safety, correctness, and predictability.
Philosophy
The shell is the most powerful tool in your arsenal and the most dangerous. A single mistyped command can delete data, kill processes, corrupt files, or expose secrets. Safety comes from discipline: understanding what a command does before running it, using dry-run modes when available, quoting variables properly, and checking exit codes. Speed is secondary to correctness.
Techniques
Avoiding Destructive Commands
- Never run
rm -rf /orrm -rf *without absolute certainty of the working directory. Verify withpwdfirst. - Before deleting, list what would be deleted:
lsthe target path or userm -i(interactive) for small sets. - Prefer
mvto a trash directory overrmwhen possible. Deletion is permanent; moving is reversible. git clean -fdxremoves all untracked files including ignored ones. Usegit clean -n(dry run) first to see what would be deleted.git reset --harddiscards all uncommitted changes. Alwaysgit stashfirst if there might be work worth keeping.chmod -R 777is almost never correct. It makes everything world-readable and writable. Use specific permissions.> filetruncates a file to zero bytes instantly. There is no undo. Redirect to a new file instead.
Proper Quoting and Escaping
- Always quote variables:
"$variable"not$variable. Unquoted variables undergo word splitting and glob expansion. - Without quotes:
rm $filewherefile="my document.txt"runsrm my document.txt— deleting two wrong files. - With quotes:
rm "$file"correctly runsrm "my document.txt". - Single quotes preserve everything literally:
'$HOME'prints$HOME, not the path. - Double quotes allow variable expansion but prevent word splitting:
"$HOME"expands to the home directory path. - Escape special characters with backslash:
\$,\",\\, ``` when needed inside double quotes. - In
find -exec, use\;to terminate the command or+for batch execution.
Understanding Exit Codes
- 0 means success. Any non-zero value means failure.
- 1 is a general error. 2 is misuse of command (wrong arguments). 126 is permission denied. 127 is command not found. 130 is terminated by Ctrl+C (SIGINT). 137 is killed (SIGKILL, often OOM).
- Check exit codes with
$?after a command, or use&&to chain dependent commands:make build && make test. - Use
set -ein scripts to exit on first error. Useset -o pipefailto catch errors in piped commands. grepreturns exit code 1 when no matches are found — this is not an error, but it will triggerset -e.
Piping and Redirection
|pipes stdout of one command to stdin of the next. Stderr is not piped — it still goes to the terminal.2>&1redirects stderr to stdout.cmd > file 2>&1captures both.cmd 2>&1 | grep errorsearches both streams.>overwrites the file.>>appends to the file. This distinction is critical.- Never redirect to the same file you are reading from:
sort file > fileresults in an empty file. Usesort file > file.sorted && mv file.sorted fileorsort -o file file. teewrites to both stdout and a file:cmd | tee output.loglets you see output and save it simultaneously.
Process Management
- Use
&to background a process. Usewaitto wait for background processes to finish. Ctrl+Csends SIGINT (interrupt).kill PIDsends SIGTERM (graceful shutdown).kill -9 PIDsends SIGKILL (immediate, non-catchable).- Check running processes with
ps auxorpgrep. Never kill processes by guessing PIDs. - Long-running commands should have timeouts:
timeout 30 commandkills the command after 30 seconds.
Working Directory Awareness
- Always know your working directory. Commands with relative paths depend entirely on it.
- Use absolute paths for critical operations:
/home/user/project/filenot./file. - When running commands in scripts, set the working directory explicitly at the start:
cd /expected/path || exit 1. - In agent contexts, the working directory may reset between commands. Do not assume it persists.
Cross-Platform Compatibility
| Operation | Bash (Linux/macOS) | PowerShell (Windows) | Notes |
|---|---|---|---|
| Null device | /dev/null | $null or NUL | Discard output |
| Path separator | / | \ (or / in many contexts) | Forward slash often works on Windows |
| List files | ls | Get-ChildItem or dir | Different output formats |
| Environment vars | $VAR or ${VAR} | $env:VAR | Different syntax |
| Line endings | LF (\n) | CRLF (\r\n) | Causes issues in scripts |
| File permissions | chmod | icacls | Fundamentally different models |
| Process search | pgrep / ps aux | Get-Process | Different filtering |
- When writing commands meant for cross-platform use, prefer tools that exist everywhere:
git,node,python,curl. - Be aware that
sed,awk,grep, andfindbehave differently between GNU (Linux) and BSD (macOS) versions. - macOS
sedrequires an explicit empty string argument for in-place editing:sed -i '' 's/a/b/'. GNUseddoes not.
Best Practices
- Preview before executing. Use
--dry-run,-n, orechoto see what a command would do before doing it. - Use version control as a safety net. Commit before running transformative commands on code. If something goes wrong, you can revert.
- Quote all variables. This is simple and prevents an entire class of bugs.
- Check exit codes. Do not assume a command succeeded. Verify with
$?or use&&chaining. - Prefer long-form flags.
rm --recursive --forceis clearer thanrm -rfand harder to mistype. - Use absolute paths for destructive operations.
rm -rf /tmp/build/is safer thanrm -rf build/because it does not depend on the working directory being correct. - Test in a safe environment first. Run commands on test data or in a sandbox before running them on production files.
Anti-Patterns
- Running commands without understanding them. Copying a command from the internet and running it without reading what each flag does.
- Suppressing errors silently. Adding
2>/dev/nullto hide errors instead of understanding and fixing them. - Using
sudoas a first resort. If a command fails with permission denied, understand why before escalating privileges. - Chaining with
;instead of&&. Usingcd /important; rm -rf *means thermruns even if thecdfails — in whatever directory you happened to be in. - Hardcoding paths. Using
/home/john/projectinstead of$HOME/projector relative paths. This breaks for every other user. - Ignoring the working directory. Running
rm -rf build/assuming you are in the project root when you might be somewhere else entirely. - Not checking if commands exist. Running
jqoryqwithout verifying they are installed. Usecommand -v jqorwhich jqto check first.
Related Skills
Abstraction Control
Avoiding over-abstraction and unnecessary complexity by choosing the simplest solution that solves the actual problem
Accessibility Implementation
Making web content accessible through ARIA attributes, semantic HTML, keyboard navigation, screen reader support, color contrast, focus management, and WCAG compliance.
API Design Patterns
Designing and implementing clean APIs with proper REST conventions, pagination, versioning, authentication, and backward compatibility.
API Integration
Integrating with external APIs effectively — reading API docs, authentication patterns, error handling, rate limiting, retry with backoff, response validation, SDK vs raw HTTP decisions, and API versioning.
Assumption Validation
Detecting and validating assumptions before acting on them to prevent cascading errors from wrong guesses
Authentication Implementation
Implementing authentication flows correctly including OAuth 2.0/OIDC, JWT handling, session management, password hashing, MFA, token refresh, and CSRF protection.