Skip to content

Instantly share code, notes, and snippets.

@msoap
Last active October 8, 2022 17:23
Show Gist options
  • Save msoap/a9ee054f80a58b16867c to your computer and use it in GitHub Desktop.
Save msoap/a9ee054f80a58b16867c to your computer and use it in GitHub Desktop.
Run Go program as script
//usr/bin/env go run $0 "$@"; exit
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Hello world!")
cwd, _ := os.Getwd()
fmt.Println("cwd:", cwd)
fmt.Println("args:", os.Args[1:])
}
@estraph
Copy link

estraph commented May 3, 2017

@msoap I'm curious about how this works. I've been digging into the shebang and magic numbers, but there doesn't seem to be official support for a // (0x2F 0x2F) magic number. My understanding is that by doing this, the executable file will be run as a shell script (somehow by default?), and that it runs the whole first line (including the //), which happens to work fine (//usr/bin/env is valid). If it was a magic number, then the // would be skipped.

Do you have any details on how this works, and how well supported it would be in mainstream shells?

UPDATE to answer my own question: if no shebang is present, and if the executable type can't otherwise be determined via a suitable magic number, then the legacy UNIX behaviour is to run the file as a script with /bin/sh. In this case, it's launching the script with sh, which in turn launches env and go run, only to exit after.

Details: http://www.faqs.org/faqs/unix-faq/faq/part3/section-16.html

Nice one!

@msoap
Copy link
Author

msoap commented May 5, 2017

Yes, run is through /bin/sh

@msoap
Copy link
Author

msoap commented Mar 16, 2018

@artheus
Copy link

artheus commented Aug 22, 2018

I would add one thing. I haven't tester that it work properly. But adding $? as argument to exit, should allow exit code to be set properly.

@msoap
Copy link
Author

msoap commented Sep 3, 2018

Unfortunately, this does not work properly. The exit code is always 1 or 0.

@jsolbrig
Copy link

@msoap There is no way to get the correct error code from go run, unfortunately. See here: https://stackoverflow.com/questions/55731760/go-os-exit2-show-a-bash-value-of-1

@pdk
Copy link

pdk commented Oct 4, 2020

I tested (very briefly) on macos with os.Exit(1) and os.Exit(7). What I see in this env is that the exit code is propagated, and can be captured with $? in the calling shell.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment