Go에서 여러 명령을 파이프하는 방법은 무엇입니까?
Go에서 여러 외부 명령을 함께 파이프하려면 어떻게해야합니까? 이 코드를 시도했지만라는 오류가 발생합니다 exit status 1
.
package main
import (
"io"
"log"
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
stdout1, err := c1.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err = c1.Start(); err != nil {
log.Fatal(err)
}
if err = c1.Wait(); err != nil {
log.Fatal(err)
}
c2 := exec.Command("wc", "-l")
c2.Stdin = stdout1
stdout2, err := c2.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err = c2.Start(); err != nil {
log.Fatal(err)
}
if err = c2.Wait(); err != nil {
log.Fatal(err)
}
io.Copy(os.Stdout, stdout2)
}
StdoutPipe는 명령이 시작될 때 명령의 표준 출력에 연결될 파이프를 반환합니다. Wait가 명령 종료를보고 나면 파이프가 자동으로 닫힙니다.
( http://golang.org/pkg/os/exec/#Cmd.StdinPipe에서 )
당신이하는 사실 c1.Wait
은 stdoutPipe
.
나는 작동하는 예제를 만들었습니다 (데모 일뿐, 오류 잡기 추가!) :
package main
import (
"bytes"
"io"
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
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)
}
간단한 시나리오의 경우 다음 접근 방식을 사용할 수 있습니다.
bash -c "echo 'your command goes here'"
예를 들어이 함수는 파이프 된 명령을 사용하여 CPU 모델 이름을 검색합니다.
func getCPUmodel() string {
cmd := "cat /proc/cpuinfo | egrep '^model name' | uniq | awk '{print substr($0, index($0,$4))}'"
out, err := exec.Command("bash","-c",cmd).Output()
if err != nil {
return fmt.Sprintf("Failed to execute command: %s", cmd)
}
return string(out)
}
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()
}
첫 번째 대답과 비슷하지만 첫 번째 명령이 시작되고 goroutine에서 기다렸습니다. 이것은 파이프를 행복하게 유지합니다.
package main
import (
"io"
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
pr, pw := io.Pipe()
c1.Stdout = pw
c2.Stdin = pr
c2.Stdout = os.Stdout
c1.Start()
c2.Start()
go func() {
defer pw.Close()
c1.Wait()
}()
c2.Wait()
}
This is a fully working example. The Execute
function takes any number of exec.Cmd
instances (using a variadic function) and then loops over them correctly attaching the output of stdout to the stdin of the next command. This must be done before any function is called.
The call function then goes about calling the commands in a loop, using defers to call recursively and ensuring proper closure of pipes
package main
import (
"bytes"
"io"
"log"
"os"
"os/exec"
)
func Execute(output_buffer *bytes.Buffer, stack ...*exec.Cmd) (err error) {
var error_buffer bytes.Buffer
pipe_stack := make([]*io.PipeWriter, len(stack)-1)
i := 0
for ; i < len(stack)-1; i++ {
stdin_pipe, stdout_pipe := io.Pipe()
stack[i].Stdout = stdout_pipe
stack[i].Stderr = &error_buffer
stack[i+1].Stdin = stdin_pipe
pipe_stack[i] = stdout_pipe
}
stack[i].Stdout = output_buffer
stack[i].Stderr = &error_buffer
if err := call(stack, pipe_stack); err != nil {
log.Fatalln(string(error_buffer.Bytes()), err)
}
return err
}
func call(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) {
if stack[0].Process == nil {
if err = stack[0].Start(); err != nil {
return err
}
}
if len(stack) > 1 {
if err = stack[1].Start(); err != nil {
return err
}
defer func() {
if err == nil {
pipes[0].Close()
err = call(stack[1:], pipes[1:])
}
}()
}
return stack[0].Wait()
}
func main() {
var b bytes.Buffer
if err := Execute(&b,
exec.Command("ls", "/Users/tyndyll/Downloads"),
exec.Command("grep", "as"),
exec.Command("sort", "-r"),
); err != nil {
log.Fatalln(err)
}
io.Copy(os.Stdout, &b)
}
Available in this gist
https://gist.github.com/tyndyll/89fbb2c2273f83a074dc
A good point to know is that shell variables like ~ are not interpolated
package main
import (
...
pipe "github.com/b4b4r07/go-pipe"
)
func main() {
var b bytes.Buffer
pipe.Command(&b,
exec.Command("ls", "/Users/b4b4r07/Downloads"),
exec.Command("grep", "Vim"),
)
io.Copy(os.Stdout, &b)
}
I spent a good day trying to use Denys Séguret answer to come up with a wrapper for multiple exec.Command
before I came across this neat package by b4b4r07.
참고URL : https://stackoverflow.com/questions/10781516/how-to-pipe-several-commands-in-go
'code' 카테고리의 다른 글
Array.join ( "\ n")은 개행 문자와 결합하는 방법이 아니십니까? (0) | 2020.12.07 |
---|---|
How can I convert Assembly.CodeBase into a filesystem path in C#? (0) | 2020.12.07 |
NSUserDefaults에서 모든 값을 얻는 방법이 있습니까? (0) | 2020.12.06 |
내 프로젝트 (Eclipse)에서 android.support.v7.widget.CardView 사용 (0) | 2020.12.06 |
빌드 도구 개정판 21.1.1을 찾지 못했습니다-최신 SDK (0) | 2020.12.06 |