Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to run Go code as a script?

Tags:

go

As Go is becoming the language of the "system". I wonder if it's possible to run Go code as a script, without compiling it, is there any possibility to do that?

The motivation (as there were questions as for motivation), taken from How to use Scala as a scripting language

Problem You want to use Scala as a scripting language on Unix systems, replacing other scripts you’ve written in a Unix shell (Bourne Shell, Bash), Perl, PHP, Ruby, etc.

UPDATE: I wonder how much I can "abuse" go run to be able to have much Go code running as scripts though compiled (which I like that its compiled) but it looks like go run can give me the opportunity to replace scripting, that is have source files on servers and run them as source while getting compiled by the go run but I still manage sources and not executables.

UPDATE: in addition saw gorun

gorun - Script-like runner for Go source files.

Though there is a motivation and tools which tried to workaround not being able to run as script, I will not go for it, +I've been told it's not production ready and was advised not to use it in production because it's not production ready, it's out of it's purpose and would need dump the scripting convenience in favour of Go. (I don't have anything against compiling, static typing, I'm a big fan of it, but wanted something similar to scripting convenience).

like image 290
Jas Avatar asked Jan 09 '17 07:01

Jas


4 Answers

I am not an expert in go, but you can do something like this. I know this is not elegant, but may be something to start with :)

~$ cat vikas.go
//usr/bin/env go run "$0" "$@"; exit

package main

import "fmt"

func main() {
    fmt.Printf("Hello World\n")
}
~$

~$ ./vikas.go
Hello World
~$
like image 80
vikas027 Avatar answered Nov 08 '22 19:11

vikas027


As others noted, Go is a compiled language. Programs written in the Go language rely on the Go runtime which is added to the executable binary.

The Go runtime provides certain vital features such as garbage collection, goroutine scheduling, runtime reflection etc. Without them a Go app cannot work as guaranteed by the language spec.

A theoretical Go interpreter would have to simulate those features, which would essentially mean to include a Go runtime and a Go compiler. There is no such thing, and there is no need for that.
Also note that if the code is not yet compiled, that means the Go interpreter would have to contain all the standard library, because a Go "script" could legally refer to anything from the standard library (when a Go app is compiled, only things that it uses / refers to gets compiled into the executable binary).

To quickly test something, just use go run, which also compiles your app and builds an executable binary in a temporary folder, launches that temp file and cleans it when your app exits.

"Solutions" posted by others may "feel" like scripting, but they are nothing more than automating / hiding the process of compiling the Go source to an executable binary and then launching that binary. This is exactly what go run does (which also cleans up the temporary binary).

like image 23
icza Avatar answered Nov 08 '22 18:11

icza


Absolutely possible on linux, props to cf: https://blog.cloudflare.com/using-go-as-a-scripting-language-in-linux

In case you don't want to use the already mentioned 'shebang' which may have limitations:

//usr/bin/env go run "$0" "$@"; exit "$?"

Do this instead:

# check if binfmt_misc is already active 
# (should already be done through systemd)
mount | grep binfmt_misc

# if not already mounted
sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

# get gorun and place it so it will work
go get github.com/erning/gorun
sudo mv $GOPATH/bin/gorun /usr/local/bin

# make .go scripts being run with `gorun` wrapper script
echo ':golang:E::go::/usr/local/bin/gorun:OC' | sudo tee /proc/sys/fs/binfmt_misc/register

This is just for one-off testing. To make this persistant, I have this as the second last line in my /etc/rc.local's:

echo ':golang:E::go::/usr/local/bin/gorun:OC' | tee /proc/sys/fs/binfmt_misc/register 1>/dev/null

If you experience something like 'caching' issues during developing scripts, have a look at /tmp/gorun-$(hostname)-USERID.

I love bash, but as soon as you need a proper datastructures (bash arrays and associative arrays don't count due to unusability) you need another language. Golang is faster to write for me than is python, and any golang setup as depicted above will do for me. No battling python 2 vs 3, its libs and pip horrors, have a distributable binary at will, and just instantly be able to change the source for small one-off scripts is why this approach has definitely its upsides.

like image 8
sjas Avatar answered Nov 08 '22 20:11

sjas


see Neugram, Go scripting . From it's documentation:

#!/usr/bin/ng

// Start a web server to serve files.
import "net/http"
pwd := $$ echo $PWD $$
h := http.FileServer(http.Dir(pwd))
http.ListenAndServe(":8080", h)
like image 3
Tomer Ben David Avatar answered Nov 08 '22 20:11

Tomer Ben David