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

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

Bo0km4n
January 28, 2019

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

Bo0km4n

January 28, 2019
Tweet

More Decks by Bo0km4n

Other Decks in Programming

Transcript

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

    View Slide

  2. 2
    About Me
    @KKawabe108
    Software Engineer
    • ઒෦ উ໵
    • ࣳӜ޻ۀେֶେֶӃ
    ిؾిࢠ৘ใ޻ֶઐ߈M1
    • όΠτઌ: ͳ͠
    • ڵຯ: OS, ෼ࢄγεςϜ, ݴޠॲཧܥ
    • ͋ͱΫϥ΢υपΓશൠ
    • ࠷ۙ࡞ͬͨ΋ͷ: ෼ࢄKVS(raft),
    ΠϯλϓϦλ

    View Slide

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

    View Slide

  4. ύοέʔδʹ͍ͭͯ
    About Go which is programming language
    • ϓϩάϥϜͷ໊લۭؒΛ෼͚ΔͨΊͷ࢓૊Έ
    • ಛఆͷॲཧΛύοέʔδʹ੾Γ෼͚Δ͜ͱͰӅṭԽΛߦ͏
    • େମଞͷݴޠͷϥΠϒϥϦ΍ύοέʔδػߏͱಉ͡ײ֮Ͱ࢖͑Δ

    View Slide

  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 }

    View Slide

  6. ͋Δ೔, ༡ΜͰ͍Δͱ
    One day, I had be coding…
    1 #include
    2 #include
    3 #include
    4 #include
    5 #include
    6 #include
    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%

    View Slide

  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 }

    View Slide

  8. 8
    όΠφϦͷ໰୊ ͳͷ͔ ࣮ߦݖݶपΓ ͳͷ͔౳৭ʑௐ΂͚ͨͲ݁ہղܾ͠ͳ͔ͬͨ

    View Slide

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

    View Slide

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

    View Slide

  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ͯ͠
    ඪ४ग़ྗʹॻ͖ࠐ·Εͨ݁Ռ΋औಘ͢Δ

    View Slide

  12. 12
    ্ख͍ͬͨ͘!!!
    Ͱ΋, ԿͰϓϩηεͷඪ४ೖྗΛม͑Δͱ্ख͘ߦ͘ͷʁ

    View Slide

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

    View Slide

  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ʹؔͯ͠͸ॳظԽ͍ͯ͠Δ

    View Slide

  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ͱ͍͏
    ؔ਺ϙΠϯλ

    View Slide

  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͢ΔͱσϑΥϧ
    τͰͦͷ໊લͷม਺Λฦ͢

    View Slide

  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

    View Slide

  18. 18
    Error: Bad file descriptor
    experiment
    ϑΝΠϧσΟεΫϦϓλʹ
    ॻ͖ࠐΈݖݶ͕෇༩͞Εͯͳ͍

    View Slide

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

    View Slide

  20. 20
    ·ͱΊ
    conclusion
    • Goͷos.execύοέʔδ͸֎෦ίϚϯυΛ࣮ߦ͢Δࡍ,
    σϑΥϧτͰඪ४ೖྗΛ/dev/nullʹઃఆ͢Δ
    • ͜ͷ࣌, Read OnlyͳͷͰॻ͖ࠐΈ͸Ͱ͖ͳ͍
    • ॻ͖ࠐΈ͍ͨ࣌͸cmd.Stdinʹॻ͖ࠐΈݖݶΛ෇༩ͨ͠σΟεΫϦϓλΛઃఆ͠Α͏

    View Slide

  21. Thank you for listening!
    Let’s fun programming
    with go!

    View Slide