0

I am trying to execute bash command "hello world" | /usr/bin/pbcopy inside go:

package main

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

func Cmd(cmd string) {
    fmt.Println("command is ", cmd)
    parts := strings.Fields(cmd)
    head := parts[0]
    parts = parts[1:len(parts)]
    out, err := exec.Command(head, parts...).Output()
    if err != nil {
        fmt.Printf("%s", err)
    }
    fmt.Println("out")
    fmt.Println(string(out))
}

func main() {
    Cmd(`echo "hello world" | /usr/bin/pbcopy`)
}

When I run this go file, it outputs:

command is  echo "hello world" | /usr/bin/pbcopy
out
"hello world" | /usr/bin/pbcopy

I expect clipboard to be equal to "hello world" but it is not.

Update

I've tried to use io.Pipe

package main

import (
    "bytes"
    "io"
    "os"
    "os/exec"
)

func main() {
    c1 := exec.Command(`echo "hello world"`)
    c2 := exec.Command("/usr/bin/pbcopy")

    r, w := io.Pipe()
    c1.Stdout = w
    c2.Stdin = r

    var b2 bytes.Buffer

    c2.Stdout = &b2

    c1.Start()
    c2.Start()
    c1.Wait()
    w.Close()
    c2.Wait()
    io.Copy(os.Stdout, &b2)
}

... but clipboard is still not equal to "hello world"

Community
  • 1
  • 1
Maxim Yefremov
  • 13,671
  • 27
  • 117
  • 166
  • The backticks around your string that you pass into `Cmd()` in the penultimate line look odd to me, maybe use single quotes rather than backticks. – Mark Setchell May 07 '15 at 08:42
  • 1
    @MarkSetchell back-ticks in Go are like single-quotes in most other languages (escape sequences are not parsed). Whereas single-quotes in Go are for rune-literals, analog to e.g. C character literals. – thwd May 07 '15 at 08:44
  • @thwd Ok, thank you - I'm always happy to defer to any who know better - it was just an idea - hence only a comment. – Mark Setchell May 07 '15 at 08:46
  • 1
    possible duplicate of [How to pipe several commands?](http://stackoverflow.com/questions/10781516/how-to-pipe-several-commands) – Ainar-G May 07 '15 at 08:54

1 Answers1

2

Command takes an executable and a list of arguments. So when you call

exec.Command(`echo "hello world"`)

That literally tries to run a command called echo "hello world" (with space and quotes). As you've already learned, exec.Command does not pass things to the shell, so "|" won't work either this way. So if you're going to piece it all together by tying the stdout and stdin together, it would look like this:

func main() {
    c1 := exec.Command("echo", "hello world")
    c2 := exec.Command("/usr/bin/pbcopy")

    c1stdout, _ := c1.StdoutPipe()
    c2stdin, _ := c2.StdinPipe()

    c1.Start()
    c2.Start()

    io.Copy(c2stdin, c1stdout)

    c2stdin.Close()
    c2.Wait()
}

But there's no need for all that. You have a shell. It can do all of this for you if you ask it to.

func main() {
    exec.Command("sh", "-c", `echo "hello world" | pbcopy`).Run()
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610