parsing the bytes from a shell program in my golang program - go

i am trying to call a shell program using golang (os/exec) but the output i am getting is in bytes and i need to convert it into float64 but it is showing error?
error: cannot convert out (type []byte) to type float64
func Cpu_usage_data() (cpu_predict float64, err error) {
out,err1 := exec.Command("/bin/sh","data_cpu.sh").Output()
if err1 != nil {
fmt.Println(err1.Error())
}
return float64(out), err1
}
data_cpu.sh is:
top -b n 1 | egrep -w 'apache2|mysqld|php' | awk '{cpu += $9}END{print cpu/NR}'

Use bytes.Buffer and strconv.ParseFloat.
func Cpu_usage_data() (cpu_predict float64, err error) {
cmd := exec.Command("/bin/sh", "data_cpu.sh")
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err != nil {
fmt.Println(err.Error())
}
cpu_predict, err = strconv.ParseFloat(out.String(), 64)
if err != nil {
fmt.Println(err.Error())
}
return
}

Related

How do I convert [][]byte to []byte?

I have a function which splits data and returns slice of subslices:
(buf []byte, lim int) [][]byte
Obviously I get an error if I do:
n, err = out.Write(split(buf[:n], 100))
The error:
cannot convert split(buf[:n], 100) (type [][]byte) to type []byte
How do I convert [][]byte to []byte?
Edit based on #Wishwa Perera: https://play.golang.org/p/nApPAYRV4ZW
Since you are splitting buf into chunks, you can pass them individually to Write by looping over the result of split.
for _, chunk := range split(buf[:n], 100) {
if _, err := out.Write(chunk); err != nil {
panic(err)
}
}
If out is a net.Conn as in your other question, then use net.Buffers to write the [][]byte.
b := net.Buffers(split(buf[:n], 100))
_, err := b.WriteTo(out)
if err != nil {
panic(err)
}

Golang SIGSEGV on *second* call only

I have a method to quickly run a shell command:
func runcmd(c string, arg ...string) (string, string, string) {
var o bytes.Buffer
var e bytes.Buffer
cmd := exec.Command(c, arg...)
cmd.Stdout = &o
cmd.Stderr = &e
err := cmd.Run()
return o.String(), e.String(), err.Error()
}
In my main have the following code:
func main() {
ver, _, exitcode := runcmd("rpm", "-q", "--queryformat", "%{VERSION}", "redhat-release")
var dist string
if exitcode != "" {
ver, _, exitcode = runcmd("rpm", "-q", "--queryformat", "%{VERSION}", "centos-release")
if exitcode != "" {
fmt.Println("Unknown OS! Exiting without running!")
os.Exit(3)
}
dist = "CentOS"
} else {
dist = "Redhat/Redhat derivative"
}
fmt.Printf("System is %s %s.\n", dist, ver)
}
Running this produces a SIGSEGV. However, when I comment the second call to runcmd it runs as normal (returning Unknown OS! Exiting without running! exit status 3). I'm new to go so i don't really understand the nil pointer dereference error to begin with, much less why it would only happen on the second call.
You are always returning err.Error(), when there is no error (err == nil) this fails with nil pointer dereference. You should do
func runcmd(c string, arg ...string) (string, string, error) {
e bytes.Buffer
cmd := exec.Command(c, arg...)
cmd.Stdout = &o
cmd.Stderr = &e
err := cmd.Run()
return o.String(), e.String(), err
}
and then
if exitcode != nil {
This is happening because of this line:
return o.String(), e.String(), err.Error()
If you are running CentOS then err := cmd.Run() will not return any error. Then err will be nil. But in return line you are returning err.Error(). You can not use access to a nil pointer. So, you are getting this error.

Shell out diff with input redirection in Golang

I'm trying to shell out something similar to:
diff <(echo -e "$string1" ) <(echo -e "$string2")
in Golang but all my attempts with exec.Command have failed.
Here is the most naive attempt I have tried (CombinedOutput is temporarily used to get the underlying issue):
func Diff(str1, str2 string) (string, error) {
cmd := exec.Command("diff", sanitize(str1), sanitize(str2))
bytes, err := cmd.CombinedOutput()
result := string(bytes)
if err != nil {
switch err.(type) {
case *exec.ExitError:
return result, nil
default:
return "", nil
}
}
return result, nil
}
Which gives me results such as: diff: \"foo\nbar\nbaz\": No such file or directory
diff: \"foo\nfighters\nbaz\": No such file or directory
A more involved version still does not work:
func Diff(str1, str2 string) (string, error) {
cmd := exec.Command("diff")
stdin, err := cmd.StdinPipe()
if err != nil {
return "", err
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return "", err
}
err = cmd.Start()
if err != nil {
return "", err
}
io.WriteString(stdin, echoString(str1))
io.WriteString(stdin, echoString(str2))
bytes, err := ioutil.ReadAll(stdout)
cmd.Wait()
result := string(bytes)
if err != nil {
switch err.(type) {
case *exec.ExitError:
return result, nil
default:
return "", nil
}
}
return result, nil
}
func echoString(str string) string {
return fmt.Sprintf(`<( echo -e "%s" )`, strings.Replace(str, `"`, `\"`, -1))
}
There is no output at all and I get diff: missing operand after `diff'
diff: Try `diff --help' for more information. in stderr.
So I thought I did not really need the echo instructions because I already got the strings, so I tried to replace echoString implementation with just the escape part, i.e. return strings.Replace(str, `"`, `\"`, -1) but I get the same error.
Any ideas?
Here is simplest solution, just pass diff command to bash shell:
cmd := exec.Command(
"bash", "-c",
fmt.Sprintf("diff <(echo -e %s) <(echo -e %s)", str1, str2))

how I can return value with a same type using exec.Command().Output()

in the next example, I am using nodejs to calculate 1+1 and I want the result with a same type of value, not string
example:
func main() {
cmd := exec.Command("/usr/bin/nodejs", "-p", "1+1")
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Println(err, stderr.String())
os.Exit(1)
}
fmt.Println(out.String())
}
is there way to do that?
When executing a command, you get a string back. You will need to deserialize it to get the proper type back. If you only expect your Node.js command to print numbers, you can use strconv.ParseFloat:
func main() {
cmd := exec.Command("/usr/bin/nodejs", "-p", "1+1")
b, err := cmd.Output()
v, err := strconv.ParseFloat(string(b), 64)
fmt.Println(v) // v is of type float64
}
If you want to handle more complex types such as javascript objects and array, I suggest serializing/deserializing node's result using JSON:
type Result struct {
Value float64
Args []float64
}
func main() {
var result Result
cmd := exec.Command("/usr/bin/nodejs", "-p", `JSON.stringify({"value": 1+1, "args": [1, 1]})`)
b, err := cmd.Output()
err = json.Unmarshal(b, &r)
fmt.Println(r.Value)
}

How do you get the output of a system command in Go?

Let's say I want to run 'ls' in a go program, and store the results in a string. There seems to be a few commands to fork processes in the exec and os packages, but they require file arguments for stdout, etc. Is there a way to get the output as a string?
There is an easier way now:
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
out, err := exec.Command("date").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out)
}
Where out is the standard output. It's in the format []byte, but you can change it to string easily with:
string(out)
You can also use CombinedOutput() instead of Output() which returns standard output and standard error.
exec.Command
To get both stdout and stderr into separate strings, you can use byte buffers like so:
cmd := exec.Command("date")
var outb, errb bytes.Buffer
cmd.Stdout = &outb
cmd.Stderr = &errb
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Println("out:", outb.String(), "err:", errb.String())
cmd := exec.Command("ls", "-al")
output, _ := cmd.CombinedOutput()
fmt.Println(string(output))
or
cmd := exec.Command(name, arg...)
stdout, err := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
if err != nil {
return err
}
if err = cmd.Start(); err != nil {
return err
}
for {
tmp := make([]byte, 1024)
_, err := stdout.Read(tmp)
fmt.Print(string(tmp))
if err != nil {
break
}
}
I used this with a recent version of GO (~1.11)
// CmdExec Execute a command
func CmdExec(args ...string) (string, error) {
baseCmd := args[0]
cmdArgs := args[1:]
log.Debugf("Exec: %v", args)
cmd := exec.Command(baseCmd, cmdArgs...)
out, err := cmd.Output()
if err != nil {
return "", err
}
return string(out), nil
}
// Usage:
// out, err := CmdExec("ls", "/home")
Two options, depending on the paradigm you prefer:
os.ForkExec()
exec.Run()
Use exec.Run, passing Pipe for stdout. Read from the pipe that it returns.
If you are wanting string output, strings.Builder is more efficient [1] than
bytes.Buffer:
package main
import (
"os/exec"
"strings"
)
func main() {
c, b := exec.Command("go", "version"), new(strings.Builder)
c.Stdout = b
c.Run()
print(b.String())
}
https://golang.org/pkg/bytes#Buffer.String
Edit: This answer is obsolete. Please see Fatih Arslan's answer below.
Use exec.Run by specifying Pipe as the stdout (and stderr if you want). It will return cmd, which contains an os.File in the Stdout (and Stderr) fields. Then you can read it using for example ioutil.ReadAll.
Example:
package main
import (
"exec";
"io/ioutil";
)
func main() {
if cmd, e := exec.Run("/bin/ls", nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil {
b, _ := ioutil.ReadAll(cmd.Stdout)
println("output: " + string(b))
}
}

Resources