How can I pipe 3+ commands together in Go (for example ls | grep | wc)? I've tried to modify this code that is for piping 2 commands, but can't figure out the correct way.,
package main
import (
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c2.Stdout = os.Stdout
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
}
https://stackoverflow.com/a/10953142/3761308
package main
import (
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("grep", "-i", "o")
c3 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c3.Stdin, _ = c2.StdoutPipe()
c3.Stdout = os.Stdout
_ = c3.Start()
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
_ = c3.Wait()
}
Related
I want to get the string length, here my code:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
fmt.Print(strconv.Itoa(len(text)))
}
For input: aaa
The output is 5 but should be 3.
I know I can just subtract -2 from the result but I want "cleaner" way
You need to remove whitespaces from your input:
import (
"fmt"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
newText := strings.TrimSpace(text)
fmt.Print(strconv.Itoa(len(newText)))
}
I want to read user input and use it as an argument for a command. I got this code:
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter img path: ")
imgPath, _ := reader.ReadString('\n')
args := []string{imgPath, "stdout", "-l spa+eng"}
out, err := exec.Command("tesseract", args...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
But when I execute it it outputs an error saying exit status 1.
If instead of using the variable imgPath as an argument I write some text directly into the array it works like a charm.
The following code returns a line with the delimiter (I work on Windows and its EOL is '\r\n'), something that wasn't shown when I printed it on the console.
reader := bufio.NewReader(os.Stdin)
imgPath, _ := reader.ReadString('\n')
In my case it ended up working after I trimmed '\r\n' from the input:
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter img path: ")
imgPath, _ := reader.ReadString('\n')
imgPath= strings.TrimRight(line, "\r\n")
args := []string{imgPath, "stdout", "-l spa+eng"}
out, err := exec.Command("tesseract", args...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
I am playing around with Go. I want to make it so when someone enters 'hi' it prints hiii
Here is my code
package main
import (
"fmt"
"bufio"
"os"
)
func main(){
reader := bufio.NewReader(os.Stdin)
fmt.Println("Simple Shell")
fmt.Println("---------------------")
for {
fmt.Print("-> ")
text, _ := reader.ReadString('\n')
if (text == "hi") {
fmt.Println("hiii")
}
}
}
There is a trick to that: When using ReadString and ReadBytes function with a delimiter, the returned string (and bytes) contains the delimiter. That's why the condition is not true, your actual string is "hi\n" and not "hi".
In order to read from stdin, you can use the ReadLine function, or manually trim the end line characters with packages strings and bytes.
Also, you can use a Scanner, it reads lines by default. Here are some examples which all do the same job:
package main
import (
"bufio"
"bytes"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("-> ")
text, _, _ := reader.ReadLine()
if string(text) == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
stext, _ := reader.ReadString('\n') // stext ends with '\n', it reads the delimiter
stext = strings.TrimRight(stext, "\n")
if stext == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
text, _ = reader.ReadBytes('\n')
text = bytes.TrimRight(text, "\n")
if string(text) == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
stext = scanner.Text()
if stext == "hi" {
fmt.Println("hii")
}
fmt.Print("−> ")
scanner.Scan()
text = scanner.Bytes()
if string(text) == "hi" {
fmt.Println("hii")
}
}
Just add \n such that
if text == "hi\n" {
fmt.Println("hiii")
}
package main
import (
"encoding/json"
"fmt"
"/something/models"
"os"
"path/filepath"
"runtime"
)
func WriteDeviceToFile(d chan *models.Device, fileName string) {
_, b, _, _ := runtime.Caller(0)
basepath := filepath.Dir(b)
filePath := basepath + "/dataFile/" + fileName
var f *os.File
var err error
f, _ = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0600)
defer f.Close()
for device := range d {
deviceB, err := json.Marshal(device)
fmt.Println(string(deviceB))
if err == nil {
if _, err = f.WriteString(string(deviceB)); err != nil {
panic(err)
}
} else {
panic(err)
}
}
}
func main() {
deviceChan := make(chan *models.Device)
go WriteDeviceToFile(deviceChan, "notalive.txt")
d := models.NewDevice("12346", "")
deviceChan <- d
d = models.NewDevice("abcd", "")
deviceChan <- d
close(deviceChan)
}
This only works with at least two devices sent to channel. With only one device in deviceChan, the function does not receive anything. Is the channel gone before the WriteDeviceToFile gets to it?
The program exits when main returns. Nothing prevents main from exiting before the files are written
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"
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()
}