name: scripting-with-go description: 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. license: AGPL-3.0-or-later metadata: author: Amolith amolith@secluded.site
Create executable Go scripts using a shell trick (not a true shebang). Scripts run directly like ./script.go with full argument support.
Basic pattern
First line of any Go script:
/**/usr/local/go/bin/go run "$0" "$@"; exit;
Then chmod +x script.go and run ./script.go args.
How it works
- OS tries to execute
./script.goas binary - Fails with ENOEXEC (not a binary)
- OS falls back to
/bin/sh - Shell runs first line: compiles and executes the script
$0= script path,$@= all argumentsexit;prevents shell from interpreting remaining Go code/**/instead of//avoids gopls formatting complaints
Complete example
/**/usr/local/go/bin/go run "$0" "$@"; exit;
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: ./script.go <name>")
os.Exit(1)
}
fmt.Printf("Hello, %s!\n", os.Args[1])
}
When to use
Good for:
- Long-lived automation needing stability (Go 1.x compatibility guarantee)
- Cross-platform scripts
- Corporate environments
- Scripts that may grow into programs
- Avoiding dependency management hell
Avoid for:
- Simple one-liners
- Systems without Go
- Throwaway scripts
Common patterns
CLI flags
/**/usr/local/go/bin/go run "$0" "$@"; exit;
package main
import (
"flag"
"fmt"
)
func main() {
verbose := flag.Bool("v", false, "verbose output")
flag.Parse()
fmt.Printf("Verbose: %v, Args: %v\n", *verbose, flag.Args())
}
stdin
/**/usr/local/go/bin/go run "$0" "$@"; exit;
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Println("Got:", scanner.Text())
}
}
File operations
/**/usr/local/go/bin/go run "$0" "$@"; exit;
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
fmt.Println(path)
}
return nil
})
}
Notes
- Adjust
/usr/local/go/bin/goif Go is elsewhere - Semicolon required in
exit;with/**/syntax - Avoid dependencies for maximum compatibility
- Slower startup than interpreted languages (compilation time)