SKILL.md

  1---
  2name: scripting-with-go
  3description: Creates executable Go scripts with shebang-like behavior.  Use when the user wants Go scripts, mentions Go scripting, or needs executable .go files. If working in a Go project, do NOT use unless explicitly requested.
  4user-invocable: true
  5license: LicenseRef-MutuaL-1.2
  6metadata:
  7  author: Amolith <amolith@secluded.site>
  8---
  9
 10Create executable Go scripts using a shell trick (not a true shebang). Scripts run directly like `./script.go` with full argument support.
 11
 12## Basic pattern
 13
 14First line of any Go script (choose based on your shell):
 15
 16```go
 17// For dash (Debian/Ubuntu default):
 18//usr/bin/env go run "$0" "$@"; exit
 19
 20// For bash/zsh (avoids gopls formatting complaints):
 21/**/usr/bin/env go run "$0" "$@"; exit;
 22```
 23
 24Then `chmod +x script.go` and run `./script.go args`.
 25
 26**Shell compatibility:**
 27- `/**/` syntax works in bash/zsh but NOT in dash
 28- `//` syntax works in dash but gopls will complain about formatting
 29- Check your `/bin/sh`: `ls -l /bin/sh`
 30- Use `//usr/bin/env go` to find go in PATH
 31- Use `//usr/local/go/bin/go` for absolute path
 32
 33## How it works
 34
 351. OS tries to execute `./script.go` as binary
 362. Fails with ENOEXEC (not a binary)
 373. OS falls back to `/bin/sh`
 384. Shell runs first line: compiles and executes the script
 395. `$0` = script path, `$@` = all arguments
 406. `exit` (or `exit;`) prevents shell from interpreting remaining Go code
 417. Shell normalizes `//path` to `/path` or `/**/path` to `/path`
 42
 43## Complete example
 44
 45```go
 46//usr/bin/env go run "$0" "$@"; exit
 47package main
 48
 49import (
 50	"fmt"
 51	"os"
 52)
 53
 54func main() {
 55	if len(os.Args) < 2 {
 56		fmt.Println("Usage: ./script.go <name>")
 57		os.Exit(1)
 58	}
 59	fmt.Printf("Hello, %s!\n", os.Args[1])
 60}
 61```
 62
 63## When to use
 64
 65**Good for:**
 66- Long-lived automation needing stability (Go 1.x compatibility guarantee)
 67- Cross-platform scripts
 68- Corporate environments
 69- Scripts that may grow into programs
 70- Avoiding dependency management hell
 71
 72**Avoid for:**
 73- Simple one-liners
 74- Systems without Go
 75- Throwaway scripts
 76
 77## Common patterns
 78
 79### CLI flags
 80
 81```go
 82//usr/bin/env go run "$0" "$@"; exit
 83package main
 84
 85import (
 86	"flag"
 87	"fmt"
 88)
 89
 90func main() {
 91	verbose := flag.Bool("v", false, "verbose output")
 92	flag.Parse()
 93	fmt.Printf("Verbose: %v, Args: %v\n", *verbose, flag.Args())
 94}
 95```
 96
 97### stdin
 98
 99```go
100//usr/bin/env go run "$0" "$@"; exit
101package main
102
103import (
104	"bufio"
105	"fmt"
106	"os"
107)
108
109func main() {
110	scanner := bufio.NewScanner(os.Stdin)
111	for scanner.Scan() {
112		fmt.Println("Got:", scanner.Text())
113	}
114}
115```
116
117### File operations
118
119```go
120//usr/bin/env go run "$0" "$@"; exit
121package main
122
123import (
124	"fmt"
125	"os"
126	"path/filepath"
127)
128
129func main() {
130	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
131		if err != nil {
132			return err
133		}
134		if !info.IsDir() {
135			fmt.Println(path)
136		}
137		return nil
138	})
139}
140```
141
142## Notes
143
144- Using `env` finds `go` in PATH, making scripts more portable
145- Semicolon required in `exit;` with `/**/` syntax (but not with `//`)
146- Avoid dependencies for maximum compatibility
147- Slower startup than interpreted languages (compilation time)