Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[CAEC MeetUp#4] Go言語におけるos/execパッケージの豆知識

0157a830bfaa0c5426422c45aa0b2637?s=47 Bo0km4n
January 28, 2019

[CAEC MeetUp#4] Go言語におけるos/execパッケージの豆知識

0157a830bfaa0c5426422c45aa0b2637?s=128

Bo0km4n

January 28, 2019
Tweet

Transcript

  1. Goͷos/execύοέʔδʹ͓͚Δ౾஌ࣝ CAEC MeetUp #4 (1/28)

  2. 2 About Me @KKawabe108 Software Engineer • ઒෦ উ໵ •

    ࣳӜ޻ۀେֶେֶӃ ిؾిࢠ৘ใ޻ֶઐ߈M1 • όΠτઌ: ͳ͠ • ڵຯ: OS, ෼ࢄγεςϜ, ݴޠॲཧܥ • ͋ͱΫϥ΢υपΓશൠ • ࠷ۙ࡞ͬͨ΋ͷ: ෼ࢄKVS(raft), ΠϯλϓϦλ
  3. Goݴޠʹ͍ͭͯ About Go which is programming language 01 03 02

    Google͕։ൃͨ͠ίϯύΠϧܕݴޠ(Ken Thompson΍Rob PikeΒ͕ઃܭͨ͠) ੩తͳܕ෇͚Λߦ͏ݴޠͰڊେͳγεςϜͰ΋։ൃతʹ΋, ύϑΥʔϚϯεతʹ΋εέʔϧ͢Δ. GoroutineΛ࢝Ίͱͨܰ͠ྔͳฒྻॲཧػߏΛαϙʔτ͢Δ ϝδϟʔͳΤσΟλͰ͸΄΅ϑΥʔϚολ͕αϙʔτ͞Ε͍ͯΔͷͰଞਓͷίʔυ͕ඇৗʹ ಡΈ΍͍͢ɹ<= ݸਓతʹܹਪ͠ϙΠϯτ
  4. ύοέʔδʹ͍ͭͯ About Go which is programming language • ϓϩάϥϜͷ໊લۭؒΛ෼͚ΔͨΊͷ࢓૊Έ •

    ಛఆͷॲཧΛύοέʔδʹ੾Γ෼͚Δ͜ͱͰӅṭԽΛߦ͏ • େମଞͷݴޠͷϥΠϒϥϦ΍ύοέʔδػߏͱಉ͡ײ֮Ͱ࢖͑Δ
  5. os/exec ύοέʔδ About os/exec package GoͰ֎෦ίϚϯυΛ࣮ߦ͢Δࡍʹ࢖͏. ࣮ࡍʹ͸GoͷϥϯλΠϜ͕goroutineΛ ࢖͍, Α͠ͳʹผϓϩηεͷڍಈΛ؅ཧ ͯ͘͠ΕΔ.

    1 package main 2 3 import ( 4 "os/exec" 5 ) 6 7 func main() { 8 cmd := exec.Command("ls", "-la") 9 if err := cmd.Run(); err != nil { 10 panic(err) 11 } 12 }
  6. ͋Δ೔, ༡ΜͰ͍Δͱ One day, I had be coding… 1 #include<stdio.h>

    2 #include<stdlib.h> 3 #include<unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 8 int main(){ 9 int result = write(0, "hello", 6); 10 if(result == -1){ 11 perror("write"); 12 exit(1); 13 } 14 printf("\nresult = %d", result); 15 return 0; 16 } ඪ४ೖྗʹhelloͱwriteγεςϜίʔϧ Ͱॻ͖ࠐΉ͚ͩͷίʔυ $ gcc sample.c -o sample $ ./sample hello result = 6%
  7. os/execܦ༝Ͱ࣮ߦ͠Α͏ͱ͢Δͱ Try execute binary via os/exec. $ go run sample_exec.go

    2019/01/21 11:01:30 exit status 1 exit status 1 Why??? 1 package main 2 3 import ( 4 "log" 5 "os/exec" 6 ) 7 8 func main() { 9 cmd := exec.Command("./sample") 10 if err := cmd.Run(); err != nil { 11 log.Fatal(err) 12 } 13 }
  8. 8 όΠφϦͷ໰୊ ͳͷ͔ ࣮ߦݖݶपΓ ͳͷ͔౳৭ʑௐ΂͚ͨͲ݁ہղܾ͠ͳ͔ͬͨ

  9. 9 TwitterͰฉ͍ͯΈͨ Help me twitter.

  10. 10 exec.Cmdߏ଄ମ exchange stdin ͔֬ʹexec.CommandͷฦΓ஋Ͱ͋Δexec.Cmdߏ଄ମ͸ඪ४ೖྗ౳ͷϝϯόΛ࣋ͬͯΔ

  11. 11 exec.Cmdͷ࣋ͭ, stdinΛૠ͛ସ͑Δ exchange stdin 1 func main() { 2

    cmd := exec.Command("./sample") 3 cmd.Stdin = os.Stdin 4 _, err := cmd.Output() 5 if err != nil { 6 log.Fatal(err) 7 } 8 } 1 $ go run sample_exec.go 2 hello 1 package main 2 3 import ( 4 "log" 5 "os/exec" 6 ) 7 8 func main() { 9 cmd := exec.Command("./sample") 10 if err := cmd.Run(); err != nil { 11 log.Fatal(err) 12 } 13 } Outputؔ਺͸Runͯ͠ ඪ४ग़ྗʹॻ͖ࠐ·Εͨ݁Ռ΋औಘ͢Δ
  12. 12 ্ख͍ͬͨ͘!!! Ͱ΋, ԿͰϓϩηεͷඪ४ೖྗΛม͑Δͱ্ख͘ߦ͘ͷʁ

  13. 13 exec.CmdपΓͷίʔυΛ௥ͬͯΈΔ investigate exec.Cmd codes.

  14. 14 Let’s go 1 func (c *Cmd) Output() ([]byte, error)

    { 2 if c.Stdout != nil { 3 return nil, errors.New("exec: Stdout already set") 4 } 5 var stdout bytes.Buffer 6 c.Stdout = &stdout 7 8 captureErr := c.Stderr == nil 9 if captureErr { 10 c.Stderr = &prefixSuffixSaver{N: 32 << 10} 11 } 12 13 err := c.Run() 14 if err != nil && captureErr { 15 if ee, ok := err.(*ExitError); ok { 16 ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes() 17 } 18 } 19 return stdout.Bytes(), err 20 } 1 func (c *Cmd) Run() error { 2 if err := c.Start(); err != nil { 3 return err 4 } 5 return c.Wait() 6 } ݁ہStartΛݺΜͰΔͷͰStartΛಡ΋͏ Cmdߏ଄ମͷඪ४ೖྗॳظԽ෦෼Λ୳͢ StdoutͱStderrʹؔͯ͠͸ॳظԽ͍ͯ͠Δ
  15. 15 Cmdߏ଄ମͷඪ४ೖྗॳظԽ෦෼Λ୳͢ Let’s go 1 func (c *Cmd) Start() error

    { 2 3 ... 4 5 type F func(*Cmd) (*os.File, error) 6 for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} { 7 fd, err := setupFd(c) 8 if err != nil { 9 c.closeDescriptors(c.closeAfterStart) 10 c.closeDescriptors(c.closeAfterWait) 11 return err 12 } 13 c.childFiles = append(c.childFiles, fd) 14 } 15 c.childFiles = append(c.childFiles, c.ExtraFiles...) 16 17 ... 18 19 } ඪ४ೖྗͷॳظԽͬΆ͍ॲཧΛݟ͚ͭͨ Cmdߏ଄ମʹඥͮ͘stdinͱ͍͏ ؔ਺ϙΠϯλ
  16. 16 Cmdߏ଄ମͷඪ४ೖྗॳظԽ෦෼Λ୳͢ Let’s go 1 func (c *Cmd) stdin() (f

    *os.File, err error) { 2 if c.Stdin == nil { 3 f, err = os.Open(os.DevNull) 4 if err != nil { 5 return 6 } 7 c.closeAfterStart = append(c.closeAfterStart, f) 8 return 9 } 10 11 if f, ok := c.Stdin.(*os.File); ok { 12 return f, nil 13 } 14 15 pr, pw, err := os.Pipe() 16 if err != nil { 17 return 18 } /dev/nullΛopenͯ͠ඪ४ೖྗ ʹׂΓ౰͍ͯͯΔʂ ͋ΕʁͰ΋/dev/null͸ writeγεςϜίʔϧͰ΋ ॻ͖ࠐΊΔ͸ͣ ౾஌ࣝ: go͸ฦΓ஋ʹ໊લΛ͚ͭΔ ͜ͱ͕Ͱ͖, return͢ΔͱσϑΥϧ τͰͦͷ໊લͷม਺Λฦ͢
  17. 17 1 2 func main() { 3 devNull, _ :=

    os.Open("/dev/null") 4 b, err := syscall.Write(int(devNull.Fd()), []byte("hello")) 5 if err != nil { 6 log.Fatal(err) 7 } 8 fmt.Println(b) 9 } ࣅͨΑ͏ͳίʔυͰ࣮ݧͯ͠ΈΔ experiment 1 go run sample_devnull.go 2 2019/01/21 13:56:03 bad file descriptor 3 exit status 1
  18. 18 Error: Bad file descriptor experiment ϑΝΠϧσΟεΫϦϓλʹ ॻ͖ࠐΈݖݶ͕෇༩͞Εͯͳ͍

  19. 19 os.OpenͷgodocΛಡΜͰΈΔͱɾɾɾ read GoDoc Read OnlyͰ։͍ͯΔ͔Βॻ͖ࠐΊͳ͔ͬͨʂʂʂ

  20. 20 ·ͱΊ conclusion • Goͷos.execύοέʔδ͸֎෦ίϚϯυΛ࣮ߦ͢Δࡍ, σϑΥϧτͰඪ४ೖྗΛ/dev/nullʹઃఆ͢Δ • ͜ͷ࣌, Read OnlyͳͷͰॻ͖ࠐΈ͸Ͱ͖ͳ͍

    • ॻ͖ࠐΈ͍ͨ࣌͸cmd.Stdinʹॻ͖ࠐΈݖݶΛ෇༩ͨ͠σΟεΫϦϓλΛઃఆ͠Α͏
  21. Thank you for listening! Let’s fun programming with go!