我想从另一个go程序中执行另一个go程序并给它args,如下所示:

1
2
3
4
package main
func main() {
  //here I want to call a specific go file, e.g. test.go with args
}

test.go

1
2
3
4
package main
func main(x int) {
  //do stuff with x
}

我不想发送一个int作为arg,但像http.ResponseWriter

我想到的解决方案,但它不会很好:

  • 使用gob将http.ResponseWriter转换为字符串
  • 从test.go读一行
  • 将字符串发送到test.go
  • 谢谢你的回答:D

    • 可能重复如何在golang中使用自定义包?
    • 它不是重复的,你提到的问题想要导入一个go源文件,这在程序运行之前已经知道,而我想加载一个go源文件/编译文件,并且只在运行时获取文件名。

    有许多方法可以实现这种互操作性:
    1-如果你有双方的源文件,我建议使用标准的golang包(Lib)调用,而不是互操作性。

    2-使用"os / exec":如果你没有源码,而你只有二进制,
    或者您可以通过文件或文本args传递args:

    你可以通过这样的args:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package main

    import (
       "fmt"
       "os"
    )

    func main() {

        fmt.Println(os.Args[0]) // fileNameAndPath
    }

    或使用"flag"std lib:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // flags.exe -h
    package main

    import (
       "flag"
       "fmt"
    )

    func main() {
        namePtr := flag.String("name","AR","name")
        agePtr := flag.Int("age", 3700,"age")
        flag.Parse()
        fmt.Println(*namePtr, *agePtr) //AR 3700
    }

    /*
    Usage of flags.exe:
      -age int
            age (default 3700)
      -name string
            name (default"AR")
    */

    这将提供-h的帮助。
    你可以像这样调用另一个二进制程序或golang编译器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package main

    import (
       "log"
       "os/exec"
    )

    func main() {
        cmnd := exec.Command("main.exe","arg")
        //cmnd.Run() // and wait
        cmnd.Start()
        log.Println("log")
    }

    3-另一种方法是使用stdin / stdout调用外部程序。
    通过这种方式,您可以通过stdin / out发送二进制数据:
    这里文件"a"调用二进制文件"b"并通过stdin / stdout发送和接收:
    这是我的转换:
    http://erlang.org/doc/tutorial/c_port.html
    (你可以使用os命名管道)
    档案a:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // a
    package main

    import (
       "fmt"
       "log"
       "os/exec"
       "runtime"
       "time"
    )

    var cout chan []byte = make(chan []byte)
    var cin chan []byte = make(chan []byte)
    var exit chan bool = make(chan bool)

    func Foo(x byte) byte { return call_port([]byte{1, x}) }
    func Bar(y byte) byte { return call_port([]byte{2, y}) }
    func Exit() byte      { return call_port([]byte{0, 0}) }
    func call_port(s []byte) byte {
        cout <- s
        s = <-cin
        return s[1]
    }

    func start() {
        fmt.Println("start")
        cmd := exec.Command("../b/b")
        stdin, err := cmd.StdinPipe()
        if err != nil {
            log.Fatal(err)
        }
        stdout, err2 := cmd.StdoutPipe()
        if err2 != nil {
            log.Fatal(err2)
        }
        if err := cmd.Start(); err != nil {
            log.Fatal(err)
        }
        defer stdin.Close()
        defer stdout.Close()
        for {
            select {
            case s := <-cout:
                stdin.Write(s)
                buf := make([]byte, 2)
                runtime.Gosched()
                time.Sleep(100 * time.Millisecond)
                stdout.Read(buf)
                cin <- buf
            case b := <-exit:
                if b {
                    fmt.Printf("Exit")
                    return //os.Exit(0)
                }
            }
        }
    }
    func main() {
        go start()
        runtime.Gosched()
        fmt.Println("30+1=", Foo(30)) //30+1= 31
        fmt.Println("2*40=", Bar(40)) //2*40= 80
        Exit()
        exit <- true
    }

    文件b:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    // b
    package main

    import (
       "log"
       "os"
    )

    func foo(x byte) byte { return x + 1 }
    func bar(y byte) byte { return y * 2 }

    func ReadByte() byte {
        b1 := make([]byte, 1)
        for {
            n, _ := os.Stdin.Read(b1)
            if n == 1 {
                return b1[0]
            }
        }
    }
    func WriteByte(b byte) {
        b1 := []byte{b}
        for {
            n, _ := os.Stdout.Write(b1)
            if n == 1 {
                return
            }
        }
    }
    func main() {
        var res byte
        for {
            fn := ReadByte()
            log.Println("fn=", fn)
            arg := ReadByte()
            log.Println("arg=", arg)
            if fn == 1 {
                res = foo(arg)
            } else if fn == 2 {
                res = bar(arg)
            } else if fn == 0 {
                return //exit
            } else {
                res = fn //echo
            }
            WriteByte(1)
            WriteByte(res)
        }
    }

    4 - 另一种方法是使用"net / rpc",这是从另一个程序调用另一个函数的最佳方法。
    样品:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    // rpc
    package main

    import (
       "fmt"
       "net"
       "net/rpc"
       "runtime"
       "sync"
    )

    var wg sync.WaitGroup

    type Server struct{}

    func (this *Server) Add(u [2]int64, reply *int64) error {
        *reply = u[0] + u[1]
        return nil
    }

    func server() {
        fmt.Println("server: Hi")
        rpc.Register(new(Server))
        ln, err := net.Listen("tcp","127.0.0.1:12345")
        if err != nil {
            fmt.Println(err)
            return
        }
        for {
            c, err := ln.Accept()
            if err != nil {
                continue
            }
            go rpc.ServeConn(c)
        }
    }

    func client() {
        wg.Add(1)
        c, err := rpc.Dial("tcp","127.0.0.1:12345")
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println("Connected...")
        var result int64
        err = c.Call("Server.Add", [2]int64{10, 20}, &result)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Println("Server.Add(10,20) =", result)
        }
        wg.Done()
    }

    func main() {
        go server()
        runtime.Gosched()
        go client()
        runtime.Gosched()
        wg.Wait()
        fmt.Println("Bye")
    }

    /*output:
    server: Hi
    Connected...
    Server.Add(10,20) = 30
    Bye
    */
    • exec.Command()真的可以执行一个带有http.ResponseWriter等参数的程序吗?此外,我只在运行时获取文件名,这就是为什么如果我正确理解你的意思,第一个解决方案将无法工作。
    • 如果你为http.ResponseWriter提供一些示例代码会更好,我认为第三种方式更适合这种情况,我会尽快添加样本
    • @LucaS。您无法序列化http.ResponseWriter,因为它的接口,包实现包含状态,并且它处理网络连接。
    • 我们走了:pastebin.com/3T1aw1xC
    • 你有双方的来源吗?
    • 我还没有编写动态页面,因为我不知道如何获得ResponseWriter和请求页面,没有这些页面将毫无价值。
    • 有什么理由你使用两个单独的程序
    • 对于某些可能有用的页面,但是当我使用单独的程序获得许多动态页面时会更清楚。
    • 所以你不需要发送http.ResponseWriter。在一台计算机内的两个程序之间进行通信的最佳方式是使用管道甚至TCP,这种方式非常简单。但是,如果从另一个程序调用另一个函数"net / rpc"是合适的方式,我想。
    • 好,谢谢!我可能会这样做。

    使用os/exec,您可以像这样调用go编译器:

    1
    2
    3
    4
    output, err := exec.Command("go","run","/file/path/to/open").Output()
    if err == nil {
        w.Write(output) // write the output with ResponseWriter
    }

    Go不会通过main将参数传递给程序,例如func main(x int)。在Go中执行此操作的方法是使用os.Args

    在我看来,你正试图在Go中使用PHP概念,这不会很好。相反,您应该使用模板和静态文件来实现动态网站。查看包text/template

    • 好吧,我有点尝试在Go中使用PHP概念,但文本/模板不符合我的标准,例如我需要根据文件和那些东西重定向

    为要从其他文件运行的程序包创建executabl文件。提供要在exec.Command中运行的文件的相对路径。例如:

    档案A.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package a

    import"fmt"

    func main(){
        for i:=0;i<10;i++{
             fmt.Println(fmt.Sprintf("Process: %d", i))
        }
    }

    为上面的文件创建二进制/可执行文件。该文件将位于包内,因此请转到包并运行可执行文件。

    1
    go build github.com/user/a/a.go // or whatever be your GOPATH for executables to create a binary file

    下面是linux系统中二进制文件的情况。

    档案B.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package b

    import (
       "fmt"
       "os/exec"
    )    

    func main(){
        // come out of package b and then go inside package a to run the executable file as
        cmd := exec.Command("../a/a.go")
        if err := cmd.Run(); err != nil{
           fmt.Println(err)
        }
    }