opencode-skills-collection 3.0.49 → 3.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +27 -1
- package/bundled-skills/ab-test-setup/SKILL.md +14 -0
- package/bundled-skills/apple-notes-search/SKILL.md +122 -0
- package/bundled-skills/astropy/references/coordinates.md +9 -0
- package/bundled-skills/astropy/references/cosmology.md +8 -0
- package/bundled-skills/astropy/references/fits.md +8 -0
- package/bundled-skills/astropy/references/tables.md +8 -0
- package/bundled-skills/astropy/references/time.md +7 -0
- package/bundled-skills/astropy/references/units.md +9 -0
- package/bundled-skills/astropy/references/wcs_and_other_modules.md +9 -0
- package/bundled-skills/browser-extension-builder/SKILL.md +1 -1
- package/bundled-skills/ckw-design/SKILL.md +129 -0
- package/bundled-skills/deterministic-design/SKILL.md +56 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/lint-and-validate/SKILL.md +3 -1
- package/bundled-skills/lookdev/SKILL.md +229 -0
- package/bundled-skills/lookdev-auto/SKILL.md +102 -0
- package/bundled-skills/macos-screen-recorder/SKILL.md +59 -0
- package/bundled-skills/pr-merge-champion/SKILL.md +116 -0
- package/bundled-skills/programmatic-seo/SKILL.md +11 -0
- package/bundled-skills/schema-markup/SKILL.md +11 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +91 -0
- package/bundled-skills/super-code/SKILL.md +209 -0
- package/bundled-skills/super-code/bash/SKILL.md +292 -0
- package/bundled-skills/super-code/c/SKILL.md +263 -0
- package/bundled-skills/super-code/cpp/SKILL.md +271 -0
- package/bundled-skills/super-code/csharp/SKILL.md +276 -0
- package/bundled-skills/super-code/dart/SKILL.md +327 -0
- package/bundled-skills/super-code/elixir/SKILL.md +366 -0
- package/bundled-skills/super-code/go/SKILL.md +234 -0
- package/bundled-skills/super-code/java/SKILL.md +230 -0
- package/bundled-skills/super-code/kotlin/SKILL.md +281 -0
- package/bundled-skills/super-code/php/SKILL.md +316 -0
- package/bundled-skills/super-code/python/SKILL.md +315 -0
- package/bundled-skills/super-code/ruby/SKILL.md +306 -0
- package/bundled-skills/super-code/rust/SKILL.md +289 -0
- package/bundled-skills/super-code/scala/SKILL.md +302 -0
- package/bundled-skills/super-code/swift/SKILL.md +299 -0
- package/bundled-skills/super-code/typescript/SKILL.md +286 -0
- package/bundled-skills/web-media-getter/SKILL.md +119 -0
- package/bundled-skills/youtube-seo-optimizer/SKILL.md +9 -9
- package/package.json +1 -1
- package/skills_index.json +574 -0
|
@@ -110,6 +110,17 @@ This is a **diagnostic score**, not a promise of rich results.
|
|
|
110
110
|
|
|
111
111
|
---
|
|
112
112
|
|
|
113
|
+
### Scoring Guidance per Category
|
|
114
|
+
|
|
115
|
+
For each of the six scoring categories, allot points within the category's weight band using these anchors:
|
|
116
|
+
|
|
117
|
+
- **0–15% of band:** Schema describes none of the visible content (e.g. you would mark `description` for a `Recipe` page that has no recipe markup yet).
|
|
118
|
+
- **16–40% of band:** Partial alignment — the schema describes some but not all of the visible content, OR maps to a less-common schema.org type.
|
|
119
|
+
- **41–80% of band:** Strong alignment — the schema describes the bulk of the visible content with a common schema.org type.
|
|
120
|
+
- **81–100% of band:** Exemplary — the schema covers all visible content, uses a Google-supported rich-result type, and includes all required properties.
|
|
121
|
+
|
|
122
|
+
Sum the per-category scores to compute the Eligibility Index used in §"Eligibility Bands" below.
|
|
123
|
+
|
|
113
124
|
### Eligibility Bands (Required)
|
|
114
125
|
|
|
115
126
|
| Score | Verdict | Interpretation |
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: screenstudio-alt
|
|
3
|
+
description: "Open-source headless Screen Studio alternative: auto speed-up of idle, auto-zoom on click clusters, keystroke overlay chips, smoothed synthetic cursor, and 9:16 vertical export that follows the action — post-production for screen recordings from the CLI."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
source_type: community
|
|
7
|
+
source_repo: connerkward/screenstudio-alternative-skill
|
|
8
|
+
date_added: "2026-06-16"
|
|
9
|
+
author: Conner K Ward
|
|
10
|
+
license: MIT
|
|
11
|
+
tags:
|
|
12
|
+
- screen-recording
|
|
13
|
+
- video
|
|
14
|
+
- post-production
|
|
15
|
+
- auto-zoom
|
|
16
|
+
- vertical-video
|
|
17
|
+
- ffmpeg
|
|
18
|
+
tools:
|
|
19
|
+
- claude-code
|
|
20
|
+
- antigravity
|
|
21
|
+
- cursor
|
|
22
|
+
- gemini-cli
|
|
23
|
+
- codex-cli
|
|
24
|
+
---
|
|
25
|
+
## When to Use
|
|
26
|
+
|
|
27
|
+
Use when polishing a screen recording / demo video for sharing, when the user mentions Screen Studio, auto-zoom, idle speed-up, or vertical/social video from a screen capture, and for any social-facing demo (vertical output is the default for those).
|
|
28
|
+
|
|
29
|
+
_Source: [connerkward/screenstudio-alternative-skill](https://github.com/connerkward/screenstudio-alternative-skill) (MIT)._
|
|
30
|
+
|
|
31
|
+
# screenstudio-alt
|
|
32
|
+
|
|
33
|
+
The skill's code lives in this directory (`polish.py`, `render.py`, `studio.py`,
|
|
34
|
+
`events-log.swift`, test fixtures, etc.). Published publicly as
|
|
35
|
+
`connerkward/screen-studio-alternative` via the publish-skill skill.
|
|
36
|
+
|
|
37
|
+
Two components:
|
|
38
|
+
|
|
39
|
+
- `events-log` (Swift) — capture-side input logger (cursor 60Hz, clicks, keys;
|
|
40
|
+
drops keys during macOS secure input). Runs ONLY while recording. Needs
|
|
41
|
+
Accessibility/Input Monitoring for the terminal. **Auto-zoom/keys/cursor need
|
|
42
|
+
this data at capture time — it cannot be recovered from pixels later.**
|
|
43
|
+
- `polish.py` (Python, ffmpeg + PIL) — the post-production pass:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python3 src/polish.py in.mp4 --events in.events.jsonl \
|
|
47
|
+
--speedup # compress idle (input-gap ∩ frozen-pixels; animations stay 1x)
|
|
48
|
+
--zoom # eased auto-zoom on click clusters (zoompan)
|
|
49
|
+
--keys # accumulating keystroke chips (PIL overlays, no drawtext dep)
|
|
50
|
+
--smooth-cursor # synthetic eased cursor (best with sck-record --no-cursor)
|
|
51
|
+
--vertical # ALSO emit 1080x1920 following the action
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`--speedup` works WITHOUT events (freezedetect only) — usable on the whole
|
|
55
|
+
existing dailies corpus.
|
|
56
|
+
|
|
57
|
+
- `render.py` — **high-quality non-destructive renderer** (preferred): single-pass
|
|
58
|
+
spring-physics camera over the original high-res frames, LANCZOS into a smaller
|
|
59
|
+
target (crisp zoom, ~1.3× sharper than the ffmpeg upscale path), 60fps, H + 9:16 V.
|
|
60
|
+
Tunable `--freq`/`--zeta` (spring), `--fps`, `--target-w`. Takes explicit
|
|
61
|
+
`--regions [{t0,t1,z,cx,cy}]`. `polish.py` is the older ffmpeg-filter fallback.
|
|
62
|
+
- `studio.py [recording.mp4]` — local web UI, **NLE-style fixed-ruler timeline** (bar =
|
|
63
|
+
source duration, never rescales → upstream always planted): zoom regions are draggable
|
|
64
|
+
blocks (move / retime edges / click to add / double-click delete); idle spans are
|
|
65
|
+
**speed blocks with rate-only editing** — source range locked, rate set via inspector
|
|
66
|
+
slider on select or right-edge **rate-stretch** drag (FCP retime / Premiere Rate
|
|
67
|
+
Stretch); rate changes ripple downstream only. Tunable cosine-ease ramp, default zoom,
|
|
68
|
+
aspect, frame styling. Always-smooth synthetic cursor + click ripple + real recorded
|
|
69
|
+
click sound (CC0 #735771). Export uses render.py. Free port, local. (Keystroke overlay
|
|
70
|
+
exists in the engine but is off by default.)
|
|
71
|
+
|
|
72
|
+
## Easy path
|
|
73
|
+
|
|
74
|
+
`screencast.sh --demo` (screencast skill) does the whole chain: starts the event
|
|
75
|
+
logger, records, then polishes + emits the 9:16 vertical automatically. Vertical
|
|
76
|
+
is the DEFAULT for social-facing demos.
|
|
77
|
+
|
|
78
|
+
## Gotchas (learned the hard way, kept here so they're not relearned)
|
|
79
|
+
|
|
80
|
+
- ffmpeg CANNOT do animated `scale=eval=frame` → `crop` (link reinit wedges crop's
|
|
81
|
+
per-frame exprs). That's why zoom uses `zoompan` (no `t` var there — use `on/FPS`).
|
|
82
|
+
- This machine's ffmpeg lacks `drawtext`; all text/cursor overlays are PIL-rendered
|
|
83
|
+
PNGs + `overlay`.
|
|
84
|
+
- Test rig: `make-fixture.py` synthesizes a fake screen recording + ground-truth
|
|
85
|
+
events.jsonl — validate any change against it before trusting real footage.
|
|
86
|
+
|
|
87
|
+
## Limitations
|
|
88
|
+
|
|
89
|
+
- The workflow assumes FFmpeg plus the companion scripts are available locally; it is not a hosted video editor.
|
|
90
|
+
- Polished cursor, click, and keystroke effects depend on event logs captured during recording; missing logs limit what can be reconstructed.
|
|
91
|
+
- Auto-zoom and idle speed-up still need human review for pacing, framing, and platform-specific taste.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: super-code
|
|
3
|
+
description: "Standing house style to enforce dense, correct, and idiomatic code on all coding tasks. Minimizes code bloat and agent operation overhead."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Super Code Skill
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Produce code that is short, correct, idiomatic, and maintainable — in that priority order.
|
|
14
|
+
This skill addresses two distinct inefficiency types that must be fixed independently:
|
|
15
|
+
|
|
16
|
+
1. **Code-token inefficiency** — the artifact itself is bloated (unnecessary lines, boilerplate, over-abstraction)
|
|
17
|
+
2. **Generation-token inefficiency** — how the agent operates during a session (full-file rewrites, unrequested files, prose padding before/after changes)
|
|
18
|
+
|
|
19
|
+
Both matter. Fixing only one is not enough.
|
|
20
|
+
|
|
21
|
+
## When to Use This Skill
|
|
22
|
+
|
|
23
|
+
- Apply this skill automatically on EVERY coding task in the IDE.
|
|
24
|
+
- Use whenever the user asks to write, edit, refactor, generate, or review code in any language.
|
|
25
|
+
- This is a standing house style, not an on-demand pass — always apply it.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Priority Order (never violate this ranking)
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Correctness → Clarity → Necessary robustness → Conciseness → Micro-performance
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Conciseness **never** wins over correctness or readability. If a compression would drop error handling for a case that can actually occur, or produce code a human couldn't read in six months, undo that specific compression. Short bad code is worse than long correct code.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Workflow — apply to every coding task
|
|
40
|
+
|
|
41
|
+
### Step 1: Commit to minimal correct shape BEFORE writing
|
|
42
|
+
|
|
43
|
+
Before touching a file, decide:
|
|
44
|
+
- What is the smallest surface area that correctly solves this problem?
|
|
45
|
+
- What does the caller actually need from this function/class/module?
|
|
46
|
+
- Is there a stdlib/framework primitive that already does this?
|
|
47
|
+
|
|
48
|
+
Write that down mentally (not in a prose block to the user). This is the target shape.
|
|
49
|
+
|
|
50
|
+
### Step 2: Write using language-idiomatic patterns
|
|
51
|
+
|
|
52
|
+
Read the relevant reference file for the language in use:
|
|
53
|
+
- Bash/Shell → `bash/SKILL.md`
|
|
54
|
+
- C → `c/SKILL.md`
|
|
55
|
+
- C++ → `cpp/SKILL.md`
|
|
56
|
+
- C# → `csharp/SKILL.md`
|
|
57
|
+
- Dart/Flutter → `dart/SKILL.md`
|
|
58
|
+
- Elixir/Erlang → `elixir/SKILL.md`
|
|
59
|
+
- Go → `go/SKILL.md`
|
|
60
|
+
- Java → `java/SKILL.md`
|
|
61
|
+
- Kotlin/Compose → `kotlin/SKILL.md`
|
|
62
|
+
- PHP → `php/SKILL.md`
|
|
63
|
+
- Python → `python/SKILL.md`
|
|
64
|
+
- Ruby → `ruby/SKILL.md`
|
|
65
|
+
- Rust → `rust/SKILL.md`
|
|
66
|
+
- Scala → `scala/SKILL.md`
|
|
67
|
+
- Swift → `swift/SKILL.md`
|
|
68
|
+
- TypeScript/JavaScript → `typescript/SKILL.md`
|
|
69
|
+
|
|
70
|
+
Apply idiomatic patterns from that file. They replace verbose imperative code with correct, concise equivalents that are still readable.
|
|
71
|
+
|
|
72
|
+
### Step 3: Compression pass on your own draft
|
|
73
|
+
|
|
74
|
+
Before presenting any code, scan it for:
|
|
75
|
+
|
|
76
|
+
| Anti-pattern | Fix |
|
|
77
|
+
|---|---|
|
|
78
|
+
| Comment restates what code does | Delete comment, or rewrite to say *why* |
|
|
79
|
+
| Single-use helper function/class | Inline it |
|
|
80
|
+
| Stdlib/framework already does this | Replace with the primitive |
|
|
81
|
+
| Defensive handling for impossible case | Remove |
|
|
82
|
+
| Verbose loop replaceable by idiomatic expression | Replace |
|
|
83
|
+
| Logging/print nobody asked for | Remove |
|
|
84
|
+
| Extra config/files/parameters not requested | Remove |
|
|
85
|
+
| Unused import or variable | Remove |
|
|
86
|
+
|
|
87
|
+
### Step 4: Guardrail check — run this before presenting
|
|
88
|
+
|
|
89
|
+
Ask yourself (silently):
|
|
90
|
+
- [ ] Did I remove handling for a case that **can** actually happen?
|
|
91
|
+
- [ ] Did I make this harder to read for a human six months from now?
|
|
92
|
+
- [ ] Did I drop correctness or security to save lines?
|
|
93
|
+
|
|
94
|
+
If yes to any: undo that specific compression and keep the rest.
|
|
95
|
+
|
|
96
|
+
### Step 5: Present output — generation-token rules
|
|
97
|
+
|
|
98
|
+
**Always:**
|
|
99
|
+
- Edit files via targeted patches/diffs, not full rewrites, unless the file is new or the change touches >70% of lines
|
|
100
|
+
- Present only what was asked for
|
|
101
|
+
|
|
102
|
+
**Never:**
|
|
103
|
+
- Generate unrequested files (tests, READMEs, configs, types) unless the user asked
|
|
104
|
+
- Add prose blocks before/after code explaining what you're about to do or just did — just do it
|
|
105
|
+
- Re-explain the user's own requirement back to them before writing
|
|
106
|
+
- Restate what changed in a paragraph after showing the diff — the diff is self-evident
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Universal Anti-Pattern Checklist
|
|
111
|
+
|
|
112
|
+
These apply in every language. The language-specific files extend this list.
|
|
113
|
+
|
|
114
|
+
### Comments
|
|
115
|
+
- ❌ `// Loop through the list and add each item` → ❌ delete
|
|
116
|
+
- ✅ `// Order matters: process refunds before charges` → ✅ keep (explains *why*)
|
|
117
|
+
- Rule: if the comment could be generated mechanically from reading the code, it adds no value
|
|
118
|
+
|
|
119
|
+
### Defensive coding
|
|
120
|
+
- Only handle error cases that can actually occur given the call site
|
|
121
|
+
- If the caller guarantees non-null, don't null-check inside the function
|
|
122
|
+
- If a catch block can only log and rethrow, consider removing the try/catch
|
|
123
|
+
|
|
124
|
+
### Abstractions
|
|
125
|
+
- Don't extract a function for logic used exactly once in one place
|
|
126
|
+
- Don't create a wrapper class around a primitive used only once
|
|
127
|
+
- Threshold: abstraction earns its place when it's used 2+ times OR when it has a meaningful name that genuinely clarifies domain logic
|
|
128
|
+
|
|
129
|
+
### Scaffolding
|
|
130
|
+
- No placeholder TODOs unless the user asked for a scaffold
|
|
131
|
+
- No `// TODO: add error handling` — either add it or don't
|
|
132
|
+
- No empty catch blocks "just in case"
|
|
133
|
+
- No parameters the current callers don't use
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Generation-Token Rules (agentic IDE specific)
|
|
138
|
+
|
|
139
|
+
These govern how you operate inside the session, not just what you produce:
|
|
140
|
+
|
|
141
|
+
### File edits
|
|
142
|
+
- Prefer surgical patches: show only the changed lines + minimal context
|
|
143
|
+
- Full file rewrite is acceptable only for: new files, files shorter than ~30 lines, or changes touching >70% of the file
|
|
144
|
+
- Never repeat unchanged portions of a file to "show the full context"
|
|
145
|
+
|
|
146
|
+
### Unrequested artifacts
|
|
147
|
+
- Do not create test files, README updates, type definition files, config files, or CI scripts unless explicitly requested
|
|
148
|
+
- If you believe a test file would be valuable, offer it in one sentence after the main output — don't generate it unasked
|
|
149
|
+
|
|
150
|
+
### Prose overhead
|
|
151
|
+
- No "Here's what I'm going to do:" preambles
|
|
152
|
+
- No "I've made the following changes:" postambles (the diff shows this)
|
|
153
|
+
- No "Let me know if you'd like me to..." closers
|
|
154
|
+
- One-line clarification is acceptable if a requirement is genuinely ambiguous; otherwise, make a reasonable choice and note the assumption in a comment inside the code if it matters
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Language Reference Files
|
|
159
|
+
|
|
160
|
+
| Language / Stack | File |
|
|
161
|
+
|---|---|
|
|
162
|
+
| Bash / Shell | `bash/SKILL.md` |
|
|
163
|
+
| C | `c/SKILL.md` |
|
|
164
|
+
| C++ | `cpp/SKILL.md` |
|
|
165
|
+
| C# / .NET | `csharp/SKILL.md` |
|
|
166
|
+
| Dart / Flutter | `dart/SKILL.md` |
|
|
167
|
+
| Elixir / Erlang | `elixir/SKILL.md` |
|
|
168
|
+
| Go | `go/SKILL.md` |
|
|
169
|
+
| Java | `java/SKILL.md` |
|
|
170
|
+
| Kotlin + Compose (Android) | `kotlin/SKILL.md` |
|
|
171
|
+
| PHP | `php/SKILL.md` |
|
|
172
|
+
| Python | `python/SKILL.md` |
|
|
173
|
+
| Ruby | `ruby/SKILL.md` |
|
|
174
|
+
| Rust | `rust/SKILL.md` |
|
|
175
|
+
| Scala | `scala/SKILL.md` |
|
|
176
|
+
| Swift (iOS/macOS) | `swift/SKILL.md` |
|
|
177
|
+
| TypeScript / JavaScript | `typescript/SKILL.md` |
|
|
178
|
+
|
|
179
|
+
Read the relevant file at Step 2. If the language isn't listed, apply the universal checklist above and use the language's own idioms for loops, error handling, and data transformation.
|
|
180
|
+
|
|
181
|
+
## Examples
|
|
182
|
+
|
|
183
|
+
### Example 1: Refactoring a verbose loop
|
|
184
|
+
```java
|
|
185
|
+
// Anti-pattern
|
|
186
|
+
List<String> names = new ArrayList<>();
|
|
187
|
+
for (User u : users) {
|
|
188
|
+
if (u.isActive()) {
|
|
189
|
+
names.add(u.getName());
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Super-code idiomatic (Java)
|
|
193
|
+
List<String> names = users.stream().filter(User::isActive).map(User::getName).toList();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Troubleshooting
|
|
197
|
+
|
|
198
|
+
### Problem: Code is too dense to read
|
|
199
|
+
**Symptoms:** Reviewer complains or logic is unreadable.
|
|
200
|
+
**Solution:** Revert the overly compressed section. Clarity and correctness always win over conciseness.
|
|
201
|
+
|
|
202
|
+
## Related Skills
|
|
203
|
+
|
|
204
|
+
- `@karpathy-guidelines` - For behavioral guidelines on surgical changes and simplicity.
|
|
205
|
+
|
|
206
|
+
## Limitations
|
|
207
|
+
|
|
208
|
+
- **Language Support:** Language-specific idioms require reference files.
|
|
209
|
+
- **Readability Tradeoffs:** Extreme compression can sometimes harm readability if not careful.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bash
|
|
3
|
+
description: "Language-specific super-code guidelines for bash."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Bash / Shell: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Quoting & Word Splitting](#quoting)
|
|
12
|
+
2. [Conditionals & Tests](#conditionals)
|
|
13
|
+
3. [Loops & Iteration](#loops)
|
|
14
|
+
4. [Pipes & Process Substitution](#pipes)
|
|
15
|
+
5. [Functions & Return Values](#functions)
|
|
16
|
+
6. [Error Handling](#errors)
|
|
17
|
+
7. [Anti-patterns specific to Bash](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Quoting & Word Splitting {#quoting}
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# ❌ Unquoted variable (word splitting + globbing)
|
|
25
|
+
for f in $files; do rm $f; done
|
|
26
|
+
|
|
27
|
+
# ✅
|
|
28
|
+
for f in "${files[@]}"; do rm -- "$f"; done
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# ❌ Unquoted command substitution
|
|
33
|
+
path=$(find . -name config)
|
|
34
|
+
cat $path # breaks on spaces
|
|
35
|
+
|
|
36
|
+
# ✅
|
|
37
|
+
path="$(find . -name config)"
|
|
38
|
+
cat "$path"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# ❌ Using backticks for command substitution
|
|
43
|
+
result=`echo hello`
|
|
44
|
+
|
|
45
|
+
# ✅ — $() nests cleanly
|
|
46
|
+
result=$(echo hello)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# ❌ String comparison without quotes
|
|
51
|
+
if [ $var = "hello" ]; then # breaks if var is empty or has spaces
|
|
52
|
+
|
|
53
|
+
# ✅
|
|
54
|
+
if [[ "$var" = "hello" ]]; then
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Rule: double-quote every `$variable` and `$(command)` unless you specifically need splitting.**
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Conditionals & Tests {#conditionals}
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# ❌ Single bracket test (POSIX but fragile)
|
|
65
|
+
if [ -f "$file" -a -r "$file" ]; then
|
|
66
|
+
|
|
67
|
+
# ✅ — [[ is safer, supports &&/||, no word splitting inside
|
|
68
|
+
if [[ -f "$file" && -r "$file" ]]; then
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# ❌ Testing command exit status with if [ $? -eq 0 ]
|
|
73
|
+
grep -q pattern file
|
|
74
|
+
if [ $? -eq 0 ]; then echo "found"; fi
|
|
75
|
+
|
|
76
|
+
# ✅ — test command directly
|
|
77
|
+
if grep -q pattern file; then echo "found"; fi
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# ❌ String equality with == outside [[
|
|
82
|
+
if [ "$a" == "$b" ]; then # == not POSIX in [ ]
|
|
83
|
+
|
|
84
|
+
# ✅
|
|
85
|
+
if [[ "$a" == "$b" ]]; then # Bash
|
|
86
|
+
# or POSIX:
|
|
87
|
+
if [ "$a" = "$b" ]; then
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# ❌ Arithmetic with [ ] and string comparison
|
|
92
|
+
if [ "$count" -gt 10 ]; then
|
|
93
|
+
|
|
94
|
+
# ✅ — (( )) for arithmetic
|
|
95
|
+
if (( count > 10 )); then
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. Loops & Iteration {#loops}
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# ❌ Parsing ls output
|
|
104
|
+
for f in $(ls *.txt); do process "$f"; done
|
|
105
|
+
|
|
106
|
+
# ✅ — glob directly
|
|
107
|
+
for f in *.txt; do
|
|
108
|
+
[[ -e "$f" ]] || continue # handle no-match
|
|
109
|
+
process "$f"
|
|
110
|
+
done
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# ❌ Reading file line-by-line with for
|
|
115
|
+
for line in $(cat file.txt); do # splits on words, not lines
|
|
116
|
+
|
|
117
|
+
# ✅
|
|
118
|
+
while IFS= read -r line; do
|
|
119
|
+
process "$line"
|
|
120
|
+
done < file.txt
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# ❌ Seq for counting
|
|
125
|
+
for i in $(seq 1 10); do
|
|
126
|
+
|
|
127
|
+
# ✅ — brace expansion (Bash)
|
|
128
|
+
for i in {1..10}; do
|
|
129
|
+
# or C-style:
|
|
130
|
+
for (( i = 1; i <= 10; i++ )); do
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# ❌ Processing command output line-by-line with pipe (subshell trap)
|
|
135
|
+
count=0
|
|
136
|
+
cat file.txt | while read -r line; do
|
|
137
|
+
(( count++ )) # count resets after loop — subshell
|
|
138
|
+
done
|
|
139
|
+
echo "$count" # always 0
|
|
140
|
+
|
|
141
|
+
# ✅ — redirect, not pipe
|
|
142
|
+
count=0
|
|
143
|
+
while IFS= read -r line; do
|
|
144
|
+
(( count++ ))
|
|
145
|
+
done < file.txt
|
|
146
|
+
echo "$count"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 4. Pipes & Process Substitution {#pipes}
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# ❌ Chained grep | grep for AND
|
|
155
|
+
grep "error" log.txt | grep "timeout"
|
|
156
|
+
|
|
157
|
+
# ✅ — single grep with pattern
|
|
158
|
+
grep -E "error.*timeout|timeout.*error" log.txt
|
|
159
|
+
# or awk for complex logic:
|
|
160
|
+
awk '/error/ && /timeout/' log.txt
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# ❌ cat + pipe (UUOC — Useless Use of Cat)
|
|
165
|
+
cat file.txt | grep pattern
|
|
166
|
+
|
|
167
|
+
# ✅
|
|
168
|
+
grep pattern file.txt
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# ❌ Temp file for diff between commands
|
|
173
|
+
cmd1 > /tmp/a.txt
|
|
174
|
+
cmd2 > /tmp/b.txt
|
|
175
|
+
diff /tmp/a.txt /tmp/b.txt
|
|
176
|
+
rm /tmp/a.txt /tmp/b.txt
|
|
177
|
+
|
|
178
|
+
# ✅ — process substitution
|
|
179
|
+
diff <(cmd1) <(cmd2)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# ❌ Ignoring pipe failures (only last command's exit code)
|
|
184
|
+
false | true
|
|
185
|
+
echo $? # 0 — false's failure hidden
|
|
186
|
+
|
|
187
|
+
# ✅
|
|
188
|
+
set -o pipefail
|
|
189
|
+
false | true
|
|
190
|
+
echo $? # 1
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 5. Functions & Return Values {#functions}
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# ❌ Using return for string values
|
|
199
|
+
get_name() {
|
|
200
|
+
return "Alice" # return is for exit codes (0-255)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# ✅ — echo + capture
|
|
204
|
+
get_name() {
|
|
205
|
+
echo "Alice"
|
|
206
|
+
}
|
|
207
|
+
name=$(get_name)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# ❌ Global variables modified inside functions
|
|
212
|
+
result=""
|
|
213
|
+
compute() { result="done"; }
|
|
214
|
+
|
|
215
|
+
# ✅ — use local, return via stdout
|
|
216
|
+
compute() {
|
|
217
|
+
local tmp
|
|
218
|
+
tmp=$(do_work)
|
|
219
|
+
echo "$tmp"
|
|
220
|
+
}
|
|
221
|
+
result=$(compute)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# ❌ Function keyword (not POSIX)
|
|
226
|
+
function my_func {
|
|
227
|
+
|
|
228
|
+
# ✅
|
|
229
|
+
my_func() {
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 6. Error Handling {#errors}
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# ❌ No error handling — script continues after failure
|
|
238
|
+
cd /some/dir
|
|
239
|
+
rm -rf * # if cd fails, deletes from wrong directory
|
|
240
|
+
|
|
241
|
+
# ✅
|
|
242
|
+
set -euo pipefail
|
|
243
|
+
|
|
244
|
+
cd /some/dir || { echo "cd failed" >&2; exit 1; }
|
|
245
|
+
rm -rf ./*
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# ❌ No cleanup on exit
|
|
250
|
+
tmpfile=$(mktemp)
|
|
251
|
+
# ... script might exit early, leaving tmpfile
|
|
252
|
+
|
|
253
|
+
# ✅ — trap for cleanup
|
|
254
|
+
tmpfile=$(mktemp)
|
|
255
|
+
trap 'rm -f "$tmpfile"' EXIT
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# ❌ Silencing errors blindly
|
|
260
|
+
command 2>/dev/null
|
|
261
|
+
|
|
262
|
+
# ✅ — redirect only when you know what you're suppressing
|
|
263
|
+
command 2>/dev/null || true # explicit: we expect and accept failure
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Start every script with `set -euo pipefail`. Remove selectively where needed.**
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 7. Anti-patterns specific to Bash {#antipatterns}
|
|
271
|
+
|
|
272
|
+
| Anti-pattern | Preferred |
|
|
273
|
+
|---|---|
|
|
274
|
+
| Parsing `ls` output | glob: `for f in *.txt` |
|
|
275
|
+
| `cat file \| grep` | `grep pattern file` |
|
|
276
|
+
| Unquoted `$var` | `"$var"` always |
|
|
277
|
+
| `[ ]` for complex tests | `[[ ]]` |
|
|
278
|
+
| Backtick substitution | `$(command)` |
|
|
279
|
+
| `$?` check after command | `if command; then` |
|
|
280
|
+
| `echo` for debug | `printf '%s\n'` (portable) |
|
|
281
|
+
| No `set -euo pipefail` | always set at script top |
|
|
282
|
+
| Temp files without cleanup | `trap 'rm -f "$tmp"' EXIT` |
|
|
283
|
+
| `eval` with user input | avoid; use arrays for dynamic commands |
|
|
284
|
+
| `#!/bin/sh` with Bash features | `#!/usr/bin/env bash` |
|
|
285
|
+
| String math `expr 1 + 1` | `$(( 1 + 1 ))` |
|
|
286
|
+
| `test -z` for number comparison | `(( ))` for arithmetic |
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
## Limitations
|
|
291
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
292
|
+
- Over-compression might reduce readability; apply judgement.
|