behave like a "cat" linux command using io/ioutil - go

have a task to creat a go file, which bahaves like cat command. I have some ideas how to do it, but i don't know how to read input if no file names written.
student#ubuntu:~/div-01/cat$ go build cat.go
student#ubuntu:~/div-01/cat$ ./cat
Hello
Hello
^C
student#ubuntu:~/div-01/cat$
Also i can use only ioutil, io, os packages and one of schools packages to print output.
In internet found this, but it just saves all input in data and then, after I press ctrl+C it prints it back.
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
var lenght int
args := os.Args[1:]
for i := range args {
lenght++
i++
}
if lenght == 0 {
data, err := ioutil.ReadAll(os.Stdin)
if err == nil {
fmt.Println(data)
}
}
}

To check the number of arguments, use len:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// No arguments give, read from STDIN.
if len(os.Args) == 1 {
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
os.Exit(1)
}
fmt.Printf("%s", data)
os.Exit(0)
}
// TODO Read the content of all files.
}

well, I found this and it works
if len(os.Args) == 1 {
_, err := io.Copy(os.Stdout, os.Stdin)
if err != nil {
fmt.Println(err)
}
fmt.Println("^C")
}

Related

GoLang tailing UTF16LE windows log file

How can I combine these two golang scripts to tail an active log that is UTF16LEBOM?
I am working on a log parser for a game (Eve Online). In the game chat logs can be saved, and I would like to use GoLang to read the running log and flag on keywords "die" in "prepare to die scumsucker!"
I've found two examples that work separately. Combining them is a challenge I've been unable to figure out. First tail equivalent here:
https://medium.com/#arunprabhu.1/tailing-a-file-in-golang-72944204f22b
Second reading the file so that is legible and doesn't have extra characters:
https://github.com/TomOnTime/utfutil/
I have been trying to replace the code from utfutil with the "equivalent" but it seems it is missing several functions.
// EDIT Almost working. It doesn't look like utfutil is defering the close.
package main
import (
"bufio"
"fmt"
"io"
"time"
"github.com/TomOnTime/utfutil"
)
func main() {
logfilefile := "C:/Users/user/Documents/EVE/logs/Chatlogs/chat_20220709_022129_1006197774.txt"
file, err := utfutil.OpenFile(logfilefile, utfutil.WINDOWS)
if err != nil {
return
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
// without this sleep you would hogg the CPU
time.Sleep(500 * time.Millisecond)
continue
}
break
}
fmt.Printf(string(line))
}
}
<cut white space>
---------------------------------------------------------------
Channel ID: local
Channel Name: Local
Listener: Steve
Session started: 2022.07.07 16:18:21
---------------------------------------------------------------
[ 2022.07.07 17:11:44 ] Steve > hello world
[ 2022.07.07 17:11:48 ] John > hello world
[ 2022.07.07 17:11:51 ] James > hello world
[ 2022.07.07 19:36:53 ] Bob > hello world
You can simplify your code by removing github.com/TomOnTime/utfutil (this is a very thin wrapper over golang.org/x/text/encoding/unicode). It's also often simpler to chain tasks rather than trying to do everything at once; here I'm borrowing tailReader (with a minor change) from this answer.
Note: I have only tested the below very quickly (and don't have an "Eve Online" logfile to hand).
package main
import (
"bufio"
"fmt"
"io"
"os"
"time"
"golang.org/x/text/encoding/unicode"
)
func main() {
file, err := newTailReader("./Local_20220707_170827_1006197774.txt")
if err != nil {
return
}
defer file.Close()
utf := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
reader := bufio.NewReader(utf.NewDecoder().Reader(file))
for {
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println(err)
break
}
fmt.Printf(string(line))
}
}
// Code copied from https://stackoverflow.com/a/31122253/11810946
// and modified to output contents of file before beginning to 'tail'
type tailReader struct {
io.ReadCloser
}
func (t tailReader) Read(b []byte) (int, error) {
for {
n, err := t.ReadCloser.Read(b)
if n > 0 {
return n, nil
} else if err != io.EOF {
return n, err
}
time.Sleep(10 * time.Millisecond)
}
}
func newTailReader(fileName string) (tailReader, error) {
f, err := os.Open(fileName)
if err != nil {
return tailReader{}, err
}
return tailReader{f}, nil
}

Continuously execute tshark from Go script

I am trying to execute tskarh from golang script using the example from
https://tutorialedge.net/golang/executing-system-commands-with-golang/
The script works fine, but i don't receive any kind of output
What i want to get is the following:
Continuously run the script,
capture some packets,
extract some fields values,
and assign to variables
Any help please ?
https://pastebin.com/PeAz7vh9
package main
import (
"fmt"
"os/exec"
"runtime"
)
func execute() {
// here we perform the pwd command.
// we can store the output of this in our out variable
// and catch any errors in err
out, err := exec.Command("tshark", "-i", "em1").CombinedOutput()
// if there is an error with our execution
// handle it here
if err != nil {
fmt.Printf("%s", err)
}
fmt.Println("Command Successfully Executed")
// as the out variable defined above is of type []byte we need to convert
// this to a string or else we will see garbage printed out in our console
// this is how we convert it to a string
output := string(out[:])
// once we have converted it to a string we can then output it.
fmt.Println(output)
}
func main() {
fmt.Println("Simple Shell")
fmt.Println("---------------------")
if runtime.GOOS == "windows" {
fmt.Println("Can't Execute this on a windows machine")
} else {
execute()
}
}
I have no idea of tshark, but here is a code that will work continously, you need os.Interrupt, and select.
package main
import (
"os"
"os/exec"
"os/signal"
)
func main() {
out := exec.Command("ping", "8.8.8.8")
f1, _ := os.OpenFile("./outfile.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
f2, _ := os.OpenFile("./errfile.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
out.Stdout = f1
out.Stderr = f2
defer func() {
f1.Close()
f2.Close()
}()
err := out.Run()
if err != nil {
panic(err)
}
var ctrlcInt chan os.Signal
ctrlcInt = make(chan os.Signal, 1)
signal.Notify(ctrlcInt, os.Interrupt)
for {
select {
case <-ctrlcInt:
break
default:
continue
}
}
return
}
this code pings 8.8.8.8 and writes out put to outfile.txt, it will exit when you press ctrl+c. If there is error it will write to errfile.txt. You can tail the files and see the output. Hope this helps.

How to create new file using go script

I am new to go lang. I am able to create a new file from the terminal using go script. like this
go run ../myscript.go > ../filename.txt
but I want to create the file from the script.
package main
import "fmt"
func main() {
fmt.Println("Hello") > filename.txt
}
If you are trying to print some text to a file one way to do it is like below, however if the file already exists its contents will be lost:
package main
import (
"fmt"
"os"
)
func main() {
err := os.WriteFile("filename.txt", []byte("Hello"), 0755)
if err != nil {
fmt.Printf("Unable to write file: %v", err)
}
}
The following way will allow you to append to an existing file if it already exists, or creates a new file if it doesn't exist:
package main
import (
"os"
"log"
)
func main() {
// If the file doesn't exist, create it, or append to the file
f, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
_, err = f.Write([]byte("Hello"))
if err != nil {
log.Fatal(err)
}
f.Close()
}
you just need to check the API documentation. This is one way to do it, there is others (with os or bufio)
package main
import (
"io/ioutil"
)
func main() {
// read the whole file at once
b, err := ioutil.ReadFile("input.txt")
if err != nil {
panic(err)
}
// write the whole body at once
err = ioutil.WriteFile("output.txt", b, 0644)
if err != nil {
panic(err)
}
}
Fprintln is pretty close to what you were trying to do:
package main
import (
"fmt"
"os"
)
func main() {
f, e := os.Create("filename.txt")
if e != nil {
panic(e)
}
defer f.Close()
fmt.Fprintln(f, "Hello")
}
https://golang.org/pkg/fmt#Fprintln

Writing buffer to file doesn't return error, so why is file empty afterwords?

I'm trying to read all standard input and write it to a file. It's writing nothing to the file provided. Why is it not working?
package main
import (
"os"
"bytes"
"fmt"
"bufio"
)
func main() {
fn := os.Args[1]
var input bytes.Buffer
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Fprintf(&input, scanner.Text())
fmt.Fprintf(&input, "\n")
}
fi, _ := os.Open(fn)
defer fi.Close()
fi.Write(input.Bytes())
}
And then...
touch writetothis.txt
echo "input text" | go run main.go writetothis.txt
# writetothis.txt is empty
Open opens a file in read-only mode.
Refer to documentation: https://golang.org/pkg/os/#Open
Instead, use OpenFile.
Also, always check for errors whenever you code. It'll save you at least weeks of work-hours in your lifetime.
Here is a working code:
package main
import (
"bufio"
"bytes"
"fmt"
"os"
)
func main() {
fn := os.Args[1]
var input bytes.Buffer
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Fprintf(&input, scanner.Text())
fmt.Fprintf(&input, "\n")
}
fmt.Println(input.Bytes())
fi, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
fmt.Println("Error with Open()",err)
}
defer fi.Close()
n, err := fi.Write(input.Bytes())
if err != nil {
fmt.Println("Error with Write()", err)
}
fmt.Println("Bytes written to file: ",n)
}
In your code you can silently fail because you aren't checking the error. It's likely a path issue. You can change your code slightly and let ioutil handle file creation so that paths aren't so much of an issue. Remember to always check the errs
package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
)
func main() {
fn := os.Args[1]
var input bytes.Buffer
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Fprintf(&input, scanner.Text())
fmt.Fprintf(&input, "\n")
}
err := ioutil.WriteFile(fn, input.Bytes(), 0644)
if err != nil {
log.Fatal(err)
}
}

How to read a text file? [duplicate]

This question already has answers here:
How can I read a whole file into a string variable
(7 answers)
Closed 4 years ago.
I'm trying to read "file.txt" and put the contents into a variable using Golang. Here is what I've tried...
package main
import (
"fmt"
"os"
"log"
)
func main() {
file, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
fmt.Print(file)
}
The file gets read successfully and the return from os.Open returns a type of *os.File
It depends on what you are trying to do.
file, err := os.Open("file.txt")
fmt.print(file)
The reason it outputs &{0xc082016240}, is because you are printing the pointer value of a file-descriptor (*os.File), not file-content. To obtain file-content, you may READ from a file-descriptor.
To read all file content(in bytes) to memory, ioutil.ReadAll
package main
import (
"fmt"
"io/ioutil"
"os"
"log"
)
func main() {
file, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer func() {
if err = file.Close(); err != nil {
log.Fatal(err)
}
}()
b, err := ioutil.ReadAll(file)
fmt.Print(b)
}
But sometimes, if the file size is big, it might be more memory-efficient to just read in chunks: buffer-size, hence you could use the implementation of io.Reader.Read from *os.File
func main() {
file, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer func() {
if err = file.Close(); err != nil {
log.Fatal(err)
}
}()
buf := make([]byte, 32*1024) // define your buffer size here.
for {
n, err := file.Read(buf)
if n > 0 {
fmt.Print(buf[:n]) // your read buffer.
}
if err == io.EOF {
break
}
if err != nil {
log.Printf("read %d bytes: %v", n, err)
break
}
}
}
Otherwise, you could also use the standard util package: bufio, try Scanner. A Scanner reads your file in tokens: separator.
By default, scanner advances the token by newline (of course you can customise how scanner should tokenise your file, learn from here the bufio test).
package main
import (
"fmt"
"os"
"log"
"bufio"
)
func main() {
file, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer func() {
if err = file.Close(); err != nil {
log.Fatal(err)
}
}()
scanner := bufio.NewScanner(file)
for scanner.Scan() { // internally, it advances token based on sperator
fmt.Println(scanner.Text()) // token in unicode-char
fmt.Println(scanner.Bytes()) // token in bytes
}
}
Lastly, I would also like to reference you to this awesome site: go-lang file cheatsheet. It encompassed pretty much everything related to working with files in go-lang, hope you'll find it useful.

Resources