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)