skills: add shell-file-editing

Recipes for ed, sed, and ssam covering the common file editing
patterns. Intended to be loaded when modifying files via execute_code
now that file_read/file_write have been removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-11 16:17:40 +02:00
parent ccc6f4d00c
commit 7da6494608
1 changed files with 336 additions and 0 deletions

336
shell-file-editing/SKILL.md Normal file
View File

@ -0,0 +1,336 @@
---
name: shell-file-editing
intent: file editing, text editing, ed, sed, ssam
description: Recipes for reading and editing files using standard Unix tools (ed, sed) and plan9port ssam. Use when modifying files via execute_code.
user-invocable: false
---
# Shell File Editing
Use `execute_code` with standard tools. Never guess line numbers — always grep first.
## Locate Before Editing
```sh
grep -n 'pattern' file # line numbers for matches
cat -n file # full file with line numbers
grep -n 'pattern' file | head # narrow to area of interest
```
## ed — Scripted Line Editing
`ed` operates on whole lines. Drive it with a heredoc; use `-s` to suppress noise.
### Address syntax
```
n line number (1-based)
$ last line
. current line (last affected)
, whole file (shorthand for 1,$)
/pattern/ next line matching pattern
?pattern? previous line matching pattern
n,m line range inclusive
/pat1/,/pat2/ range from first match to second
```
### Substitute on a matching line
```sh
ed -s file <<'EOF'
/pattern/s/old/new/
w
q
EOF
```
### Global substitute (all occurrences in file)
```sh
ed -s file <<'EOF'
,s/old/new/g
w
q
EOF
```
### Delete lines matching a pattern
```sh
ed -s file <<'EOF'
g/pattern/d
w
q
EOF
```
### Delete a line range
```sh
ed -s file <<'EOF'
5,10d
w
q
EOF
```
### Insert text before a matching line
```sh
ed -s file <<'EOF'
/pattern/i
new line of text
.
w
q
EOF
```
### Append text after a matching line
```sh
ed -s file <<'EOF'
/pattern/a
new line of text
.
w
q
EOF
```
### Replace a range of lines
```sh
ed -s file <<'EOF'
/start_pattern/,/end_pattern/c
replacement line 1
replacement line 2
.
w
q
EOF
```
### Replace exact line range
```sh
ed -s file <<'EOF'
3,7c
new content
.
w
q
EOF
```
### Append at beginning of file (address 0)
```sh
ed -s file <<'EOF'
0a
first line
.
w
q
EOF
```
### Move lines
```sh
ed -s file <<'EOF'
5,8m12
w
q
EOF
```
### Print without modifying (verify before write)
```sh
ed -s file <<'EOF'
,p
q
EOF
```
### Multi-step script
```sh
ed -s file <<'EOF'
/^func foo/,/^}/c
func foo(x int) int {
return x * 2
}
.
,s/OldName/NewName/g
w
q
EOF
```
### Key points
- Input mode (`a`, `i`, `c`) ends with a lone `.` on its own line
- `g/re/cmd` runs cmd on every matching line; useful with `d`, `s`, `p`
- `wq` writes and quits in one command
- Substitute delimiter can be any non-space non-newline character: `s|/path/a|/path/b|`
- `\n` in replacement introduces a newline (splits the line)
---
## sed — Stream Substitution
Best for simple in-place substitutions. Single-pass; cannot insert multi-line
blocks as easily as ed.
### In-place substitution (GNU sed)
```sh
sed -i 's/old/new/g' file
```
### In-place on multiple files
```sh
sed -i 's/old/new/g' *.go
```
### Substitute only on lines matching a pattern
```sh
sed -i '/pattern/s/old/new/' file
```
### Delete lines matching a pattern
```sh
sed -i '/pattern/d' file
```
### Delete a line range
```sh
sed -i '5,10d' file
```
### Print a line range (no modification)
```sh
sed -n '10,20p' file
```
### Multiple expressions
```sh
sed -i -e 's/foo/bar/g' -e 's/baz/qux/g' file
```
### Address forms
```
n line n
$ last line
/regexp/ lines matching regexp
n,m range
/a/,/b/ range between patterns
n,+k line n and k lines after it
```
### Key points
- GNU sed: `-i` with no suffix. BSD sed: `-i ''`. Prefer `ed` for portability.
- sed makes one pass; edits to earlier lines do not affect later address matching
- Use `ed` when inserting or replacing blocks of multiple lines
---
## ssam — Structural Editing (plan9port)
`ssam` uses sam's command language. Selects structurally (by regex), not by
line number. Entire input is loaded before the script runs.
Check availability: `command -v ssam`
### Basic syntax
```
ssam 'address command' file
ssam -n 'address command' file # suppress default output
```
On invocation, the entire file is selected (dot = `,`).
### Address syntax
```
, whole file
n line n
/regexp/ next match of regexp
?regexp? previous match
#n character offset n (#0 = start of file)
$ end of file
. current selection (dot)
a1,a2 from start of a1 to end of a2
```
### Print first 10 lines
```sh
ssam -n ',10p' file
```
### Global substitution
```sh
ssam 's/old/new/g' file
```
### Substitute within lines matching a pattern
```sh
ssam 'x/.*pattern.*\n/ s/old/new/' file
```
### Delete empty lines
```sh
ssam 's/\n\n+/\n/g' file
```
### Print one word per line
```sh
ssam -n 'y/[a-zA-Z]+/ c/\n/' file
```
### Structural loop: run command on each match
```sh
# x selects each match of the pattern, then runs the sub-command on it
ssam 'x/pattern/ c/replacement/' file
```
### Conditional: run command only if range contains match
```sh
ssam 'g/pattern/ s/old/new/' file # only lines containing pattern
ssam 'v/pattern/ s/old/new/' file # only lines NOT containing pattern
```
### Key points
- ssam consumes all of stdin before running; safe for in-place style pipelines
- `x/re/ cmd` iterates over all non-overlapping matches; nested `x` is legal
- `y/re/ cmd` iterates over the text *between* matches
- `g/re/ cmd` and `v/re/ cmd` are guards (if-contains / if-not-contains)
- To write back in place: `ssam 'script' file > tmp && mv tmp file`
---
## Workflow
1. Locate with `grep -n` or `cat -n`
2. Preview the change with `ed -s file <<'EOF'\n,p\nq\nEOF` or `sed -n`
3. Apply the edit
4. Verify with `grep` or `cat -n` that the change landed correctly