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)