I'm new to Go and I've the following problem. I need to use os.exec to interact with the powershell and capture the output per command/pipe in it.
Eg I have the following command
powershell /C cat somefile.md | Select-String -Pattern someinput
I need the output of the first command
powershell /C cat somefile.md
and the output of the pipe
powershell /C Select-String -Pattern someinput
The code below works fine on linux and with cmd on Windows, I have to use powershell tho...
Edit: After further investigation I came to the conclusion that Select-String
and other powershell specific commands are just not pipe-able, for whatever reason. Is it because powershell needs an PSObject as input?
That's my messy code right now:
func executeCmds{
//save all exec.Commands in one array (I've no clue how many cmds there are later)
var cmdList []exec.Cmds
cmdList = append(cmdList, *exec.Command("powershell", "/C", "cat somefile.md"))
//*****EDIT*****//
// not working $Input is missing
cmdList = append(cmdList, *exec.Command("powershell", "/C", "Select-String -Pattern someinput"))
// working command $Input is important
cmdList = append(cmdList, exec.Command("powershell", "/C", "$Input | Select-String -Pattern someinput"))
// this is performance wise NOT an option!
// cmdList = append(cmdList, *exec.Command("powershell", "/C", "cat somefile.md | Select-String -Pattern someinput"))
// save the latest stdout into tmp to stdin the next command (works fine on linux and cmd.exe)
var tmp []byte
for i, s := range cmdList {
if i > 0 {
s.Stdin = strings.NewReader(string(tmp)) //this does not work, powershell somehow can't use Stdin
}
stdout, err := s.CombinedOutput()
tmp = stdout
if err != nil {
o := fmt.Sprint(err) + ": " + string(stdout)
err = errors.New(o)
panic(err)
break
}
// Print the output
fmt.Println(string(stdout))
}
}
You dont need to use PowerShell for this, you can just use Go directly:
package main
import "golang.org/x/sys/windows/registry"
func main() {
a, e := registry.CURRENT_USER.ReadSubKeyNames(0)
if e != nil {
panic(e)
}
for _, s := range a {
println(s)
}
}
If you need to pass the data through a go application then you can do something like the following (I'm not sure how this will improve performance over using the powershell pipeline):
package main
import (
"fmt"
"io"
"os/exec"
)
func main() {
// save all exec.Commands in one array (I've no clue how many cmds there are later)
var cmdList []*exec.Cmd
cmdList = append(cmdList, exec.Command("powershell", "/C", "cat somefile.md"))
cmdList = append(cmdList, exec.Command("powershell", "/C", "$Input | Select-String -Pattern someinput"))
var tmp []byte
for i, s := range cmdList {
if i > 0 { // Send the output of the previous command into the next command
input, err := s.StdinPipe()
if err != nil {
panic(err)
}
go func(w io.WriteCloser, data []byte) {
w.Write(data) // Should really check for errors here
w.Close()
}(input, tmp)
}
var err error
tmp, err = s.CombinedOutput() // As you are taking standard error here too you should check for errors
if err != nil {
panic(err)
}
}
// Print the final output
fmt.Println(string(tmp))
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.