Golang for loop wont stop - go

So I am starting to learn the Go Programming Language and was hoping someone might be able to clarify why I'm getting the results I'm getting. I'm trying to have the program read input from the user and display it back until the user only enters the newline character.
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main(){
inputBuff := bufio.NewReader(os.Stdin)
line,_ := inputBuff.ReadString('\n')
for (!strings.EqualFold(line,"\n")){
line,err := inputBuff.ReadString('\n')
if err!=nil {
fmt.Println(err)
}
fmt.Println(line)
fmt.Println(!strings.EqualFold(line,"\n"))
}
}
I am trying to read in full strings at a time so i thought the bufio would be better the using Scan. I added the last print to show that the method is returning false but the loop continues to execute. Any help would be greatly appreciated.

the line inside the loop is not the same line you initiated for the check. FTFY:
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main(){
inputBuff := bufio.NewReader(os.Stdin)
line,_ := inputBuff.ReadString('\n')
var err error
for (!strings.EqualFold(line,"\n")){
line,err = inputBuff.ReadString('\n')
if err!=nil {
fmt.Println(err)
}
fmt.Println(line)
fmt.Println(!strings.EqualFold(line,"\n"))
}
You used the := assignment operator inside the loop, as in line, err := .....
This makes Go create a new symbol inside the the for loop with the name line. But the for's check is outside the inner scope of the loop code block. So it refers to the old line that was initiated outside the loop.
Changing the operator inside the loop to = doesn't create a new variable, but also doesn't init err, so I defined it beforehand too. err can be declared inside the loop but that's redundant.

Related

Is there a way to allow a user to delete a full word while reading a line in Go?

I am trying to create a shell in Go. I currently have this code that reads the os.Stdin and prints it out.
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
buf := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
bytes, err := buf.ReadBytes('\n')
if err != nil {
panic(err)
}
fmt.Println(strings.TrimSuffix(string(bytes), "\n"))
}
}
However, while you are typing out your commands, I found that you can not use Command + Backspace to delete a full word like you can usually do in a shell. I found this issue to be pretty annoying and after looking at other similar questions on StackOverflow I saw that some people mentioned that the terminal needs to be in raw mode.
I have tried using termbox-go, but I was not able to get it working. If anyone could point me in the right direction it would be greatly appreciated.
Thanks.

Detecting whether something is on STDIN

Program should be able to get input from stdin on terminal, as follows:
echo foobar | program
However, in the source below for Program, the stdin read blocks if the pipe is omitted:
package main
import (
"fmt"
"os"
)
func main() {
b := make([]byte, 1024)
r := os.Stdin
n, e := r.Read(b)
if e != nil {
fmt.Printf("Err: %s\n", e)
}
fmt.Printf("Res: %s (%d)\n", b, n)
}
So how can Program detect whether something is being piped to it in this manner, and continue execution instead of blocking if not?
... and is it a good idea to do so?
os.Stdin is treated like a file and has permissions. When os.Stdin is open, the perms are 0600, when closed it's 0620.
This code works:
package main
import (
"fmt"
"os"
)
func main() {
stat, _ := os.Stdin.Stat()
fmt.Printf("stdin mode: %v\n", stat.Mode().Perm())
if stat.Mode().Perm() == 0600 {
fmt.Printf("stdin open\n")
return
}
fmt.Printf("stdin close\n")
}
It would be possible if you put the read in a goroutine and use select to do a non-blocking read from the channel in main, but you would then have a race condition where you could get different results depending on whether the data comes in quickly enough. What is the larger problem you're trying to solve?

How to read multiple times from same io.Reader

I want to use request.Body(type io.ReadCloser) which is containing a image.
I dont want to use ioutil.ReadAll() as i want to write this body directly to the file as well as want to decode it, so i only want to use the reference to the content to pass to further function calls,
I tried creating multiple instances of reader for example shown below
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
a := &r
b := &r
log.Println(ioutil.ReadAll(*a))
log.Println(ioutil.ReadAll(*b))
}
but in second call it always results into nil.
Please help me how can i pass multiple separate reference for the same reader?
io.Reader is treated like a stream. Because of this you cannot read it twice. Imagine an incoming TCP connection - you cannot rewind what's coming in.
But you can use the io.TeeReader to duplicate the stream:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
log.Println(ioutil.ReadAll(tee))
log.Println(ioutil.ReadAll(&buf))
}
Example on Go Playground
Edit: As #mrclx pointed out: You need to read from the TeeReader first, otherwise the buffer will be empty.
When you call ReadAll it's going to empty the buffer, so the second call will always return nothing. What you could do is save the result of ReadAll and reuse that in your functions. For example:
bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))
When you read from ioutil.ReadAll(r) then, the content is gone. You can’t read from it a second time.
For an example:
var response *http.Response
//Read the content
rawBody, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Error(err)
}
// Restore the io.ReadCloser to it's original state
response.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))
Technically, on one reader, you cannot read multiple times.
Even if you create different references but
when you read once it will be same object referred by all references.
so what you can do is read the content and store it in one variable.
Then use that variable as many times as you want.
This will print twice.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
stringData, _ := ioutil.ReadAll(r)
log.Println(stringData)
log.Println(stringData)
}
Clone the Reader struct.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
v := new(strings.Reader)
*v = *r
log.Println(ioutil.ReadAll(r))
log.Println(ioutil.ReadAll(v))
}

golang read line by line

I've started studying golang a bit and I'm absolutely unable to understand how I'm supposed to read line by line in the old-fashioned way:
while filehandler != EOF {
line_buffer = readline(filehandler)
}
I'm aware that I have to use bufio scanlines. This isn't what I am using as code, I'm merely trying to explain the idea.
use this:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, _ := os.Open("path/to_file")
fscanner := bufio.NewScanner(file)
for fscanner.Scan() {
fmt.Println(fscanner.Text())
}
}

Communication with other Go process

I have a program that reads a filename from the console and executes go run filename.go.
// main.go
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
console := bufio.NewReader(os.Stdin)
fmt.Print("Enter a filename: ")
input, err := console.ReadString('\n')
if err != nil {
log.Fatalln(err)
}
input = input[:len(input)-1]
gorun := exec.Command("go", "run", input)
result, err := gorun.Output()
if err != nil {
log.Println(err)
}
fmt.Println("---", input, "Result ---")
fmt.Println(string(result))
}
In the same directory, I have another file like this.
// hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
When I input "hello.go" in the console, that file is run, and its output gets returned to the parent Go process. However, I have another program like this.
// count.go
package main
import (
"fmt"
"time"
)
func main() {
i := 0
for {
time.Sleep(time.Second)
i++
fmt.Println(i)
}
}
Except, because this program never returns, my parent process is left hanging forever. Is there a way to communicate with different Go processes? I'm thinking something like channels for goroutines, but for processes. I need to be able to receive live stdout from the child process.
The problem I'm trying to solve is dynamically executing Go programs from a directory. Go files will be added, removed, and modified daily. I'm kind of trying to make something like Go Playgrounds. The main process is a webserver serving webpages, so I can't shut it down all the time to modify code.
Don't use go run, you need to do what go run is doing yourself to have the go program be a direct child of your server process.
Using go build -o path_to/binary source_file.go will give you more control. Then you can can directly execute and communicate with the resulting binary.

Resources