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.
  4license: AGPL-3.0-or-later
  5metadata:
  6  author: Amolith <amolith@secluded.site>
  7---
  8
  9Create executable Go scripts using a shell trick (not a true shebang). Scripts run directly like `./script.go` with full argument support.
 10
 11## Basic pattern
 12
 13First line of any Go script:
 14
 15```go
 16/**/usr/local/go/bin/go run "$0" "$@"; exit;
 17```
 18
 19Then `chmod +x script.go` and run `./script.go args`.
 20
 21## How it works
 22
 231. OS tries to execute `./script.go` as binary
 242. Fails with ENOEXEC (not a binary)
 253. OS falls back to `/bin/sh`
 264. Shell runs first line: compiles and executes the script
 275. `$0` = script path, `$@` = all arguments
 286. `exit;` prevents shell from interpreting remaining Go code
 297. `/**/` instead of `//` avoids gopls formatting complaints
 30
 31## Complete example
 32
 33```go
 34/**/usr/local/go/bin/go run "$0" "$@"; exit;
 35package main
 36
 37import (
 38	"fmt"
 39	"os"
 40)
 41
 42func main() {
 43	if len(os.Args) < 2 {
 44		fmt.Println("Usage: ./script.go <name>")
 45		os.Exit(1)
 46	}
 47	fmt.Printf("Hello, %s!\n", os.Args[1])
 48}
 49```
 50
 51## When to use
 52
 53**Good for:**
 54- Long-lived automation needing stability (Go 1.x compatibility guarantee)
 55- Cross-platform scripts
 56- Corporate environments
 57- Scripts that may grow into programs
 58- Avoiding dependency management hell
 59
 60**Avoid for:**
 61- Simple one-liners
 62- Systems without Go
 63- Throwaway scripts
 64
 65## Common patterns
 66
 67### CLI flags
 68
 69```go
 70/**/usr/local/go/bin/go run "$0" "$@"; exit;
 71package main
 72
 73import (
 74	"flag"
 75	"fmt"
 76)
 77
 78func main() {
 79	verbose := flag.Bool("v", false, "verbose output")
 80	flag.Parse()
 81	fmt.Printf("Verbose: %v, Args: %v\n", *verbose, flag.Args())
 82}
 83```
 84
 85### stdin
 86
 87```go
 88/**/usr/local/go/bin/go run "$0" "$@"; exit;
 89package main
 90
 91import (
 92	"bufio"
 93	"fmt"
 94	"os"
 95)
 96
 97func main() {
 98	scanner := bufio.NewScanner(os.Stdin)
 99	for scanner.Scan() {
100		fmt.Println("Got:", scanner.Text())
101	}
102}
103```
104
105### File operations
106
107```go
108/**/usr/local/go/bin/go run "$0" "$@"; exit;
109package main
110
111import (
112	"fmt"
113	"os"
114	"path/filepath"
115)
116
117func main() {
118	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
119		if err != nil {
120			return err
121		}
122		if !info.IsDir() {
123			fmt.Println(path)
124		}
125		return nil
126	})
127}
128```
129
130## Notes
131
132- Adjust `/usr/local/go/bin/go` if Go is elsewhere
133- Semicolon required in `exit;` with `/**/` syntax
134- Avoid dependencies for maximum compatibility
135- Slower startup than interpreted languages (compilation time)