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
 28- `/**/` syntax works in bash/zsh but NOT in dash
 29- `//` syntax works in dash but gopls will complain about formatting
 30- Check your `/bin/sh`: `ls -l /bin/sh`
 31- Use `//usr/bin/env go` to find go in PATH
 32- Use `//usr/local/go/bin/go` for absolute path
 33
 34## How it works
 35
 361. OS tries to execute `./script.go` as binary
 372. Fails with ENOEXEC (not a binary)
 383. OS falls back to `/bin/sh`
 394. Shell runs first line: compiles and executes the script
 405. `$0` = script path, `$@` = all arguments
 416. `exit` (or `exit;`) prevents shell from interpreting remaining Go code
 427. Shell normalizes `//path` to `/path` or `/**/path` to `/path`
 43
 44## Complete example
 45
 46```go
 47//usr/bin/env go run "$0" "$@"; exit
 48package main
 49
 50import (
 51	"fmt"
 52	"os"
 53)
 54
 55func main() {
 56	if len(os.Args) < 2 {
 57		fmt.Println("Usage: ./script.go <name>")
 58		os.Exit(1)
 59	}
 60	fmt.Printf("Hello, %s!\n", os.Args[1])
 61}
 62```
 63
 64## When to use
 65
 66**Good for:**
 67
 68- Long-lived automation needing stability (Go 1.x compatibility guarantee)
 69- Cross-platform scripts
 70- Corporate environments
 71- Scripts that may grow into programs
 72- Avoiding dependency management hell
 73
 74**Avoid for:**
 75
 76- Simple one-liners
 77- Systems without Go
 78- Throwaway scripts
 79
 80## Common patterns
 81
 82### CLI flags
 83
 84```go
 85//usr/bin/env go run "$0" "$@"; exit
 86package main
 87
 88import (
 89	"flag"
 90	"fmt"
 91)
 92
 93func main() {
 94	verbose := flag.Bool("v", false, "verbose output")
 95	flag.Parse()
 96	fmt.Printf("Verbose: %v, Args: %v\n", *verbose, flag.Args())
 97}
 98```
 99
100### stdin
101
102```go
103//usr/bin/env go run "$0" "$@"; exit
104package main
105
106import (
107	"bufio"
108	"fmt"
109	"os"
110)
111
112func main() {
113	scanner := bufio.NewScanner(os.Stdin)
114	for scanner.Scan() {
115		fmt.Println("Got:", scanner.Text())
116	}
117}
118```
119
120### File operations
121
122```go
123//usr/bin/env go run "$0" "$@"; exit
124package main
125
126import (
127	"fmt"
128	"os"
129	"path/filepath"
130)
131
132func main() {
133	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
134		if err != nil {
135			return err
136		}
137		if !info.IsDir() {
138			fmt.Println(path)
139		}
140		return nil
141	})
142}
143```
144
145## Notes
146
147- Using `env` finds `go` in PATH, making scripts more portable
148- Semicolon required in `exit;` with `/**/` syntax (but not with `//`)
149- Avoid dependencies for maximum compatibility
150- Slower startup than interpreted languages (compilation time)