8

I'm trying to cross compile a Go program that will execute a bash script. Is it possible to embed the bash script in the binary?

I've referenced: Golang serve static files from memory

Not sure if this applies to executing bash scripts though. Am I missing something here? Some clarification or pointers will be very helpful, thanks!

Community
  • 1
  • 1
user3918985
  • 4,278
  • 9
  • 42
  • 63

3 Answers3

7

Since bash can execute scripts from stdin, you just send your script to the bash command via command.Stdin.

An example without go embed:

package main

import (
    "bytes"
    "fmt"
    "os/exec"
    "strings"
)

var script = `
echo $PWD
pwd
echo "-----------------------------------"
# print process
ps aux | grep code
`

func main() {
    c := exec.Command("bash")
    c.Stdin = strings.NewReader(script)

    b, e := c.Output()
    if e != nil {
        fmt.Println(e)
    }
    fmt.Println(string(b))
}

With go 1.16 embed (https://golang.org/pkg/embed/):

package main

import (
    "bytes"
    _ "embed"
    "fmt"
    "os/exec"
    "strings"
)

//go:embed script.sh
var script string

func main() {
    c := exec.Command("bash")
    c.Stdin = strings.NewReader(script)

    b, e := c.Output()
    if e != nil {
        fmt.Println(e)
    }
    fmt.Println(string(b))
}

Bonus

Passing parameters to your script with -s -.

The following example will pass -la /etc to the script.

package main

import (
    "fmt"
    "os/exec"
    "strings"
)

func main() {
    // pass parameters to your script as a safe way.
    c := exec.Command("sh", "-s", "-", "-la", "/etc")

    // use $1, $2, ... $@ as usual
    c.Stdin = strings.NewReader(`
    echo $@
    ls $1 "$2"
    `)

    b, e := c.Output()
    if e != nil {
        fmt.Println(e)
    }
    fmt.Println(string(b))
}

Playground: https://go.dev/play/p/T1lMSrXcOIL

ninhjs.dev
  • 7,203
  • 1
  • 49
  • 35
0

You can actually directly interface with the system shell in Go. Depending on what's in your bash script you can probably convert everything completely to go. For example things like handling files, extracting archives, outputting text, asking for user input, downloading files, and so much more can be done natively in Go. For anything you absolutely need the shell for you can always use golang.org/pkg/os/exec.

I wrote a snippet that demonstrates a really simple Go based command shell. Basically it pipes input, output, and error between the user and the shell. It can be used interactively or to directly run most shell commands. I'm mentioning it here mostly to demonstrate Go's OS capabilities. Check it out: github.com/lee8oi/goshell.go

lee8oi
  • 1,169
  • 8
  • 12
-1

Did you try writing the stream-data (according to the reference go-bindata provides a function that returns []byte) into a temporary file?

see: http://golang.org/pkg/io/ioutil/#TempFile

you can then execute it with a syscall

http://golang.org/pkg/syscall/#Exec

where the first argument needs to be a shell.

krizz
  • 412
  • 3
  • 5
  • Do *not* use `syscall.Exec` when [the `os/exec` package](https://golang.org/pkg/os/exec/) will do. Do *not* use temporary files when there is no need. – Dave C Apr 12 '15 at 05:47