Slide 1

Slide 1 text

How to execute external programs in Perl Shoichi Kaji

Slide 2

Slide 2 text

About Me • Shoichi Kaji • One of the maintainers of
 Minilla, Perl::Build, Text::Xslate, Mouse, Test::PAUSE::Permissions

Slide 3

Slide 3 text

͸͡Ίʹ • Perl͸betterγΣϧͱݺ͹ΕΔ • ΑͬͯPerlͰ֎෦ϓϩάϥϜΛ࣮ߦ͢Δػձ͸ଟ͍ • ҰํͰ֎෦ϓϩάϥϜ࣮ߦ͸ߟྀ͢΂͖͜ͱ͕
 ͨ͘͞Μ͋Δ • ࢥ͍ͷ··ʹ֎෦ϓϩάϥϜΛ࣮ߦͰ͖ΔΑ͏ʹ ͳΓ͍ͨ

Slide 4

Slide 4 text

Perlͷ֎෦ϓϩάϥϜ࣮ߦؔ࿈ͷ
 τϐοΫε • shellΛհ͢΂͔Βͣ ←ࠓ೔͸͜͜ͱ • redirect, pipe ←͜͜Λѻ͏ • γάφϧ • Windows

Slide 5

Slide 5 text

໨࣍ • shellΛհ͢΂͔Βͣ • ֎෦ϓϩάϥϜΛ࣮ߦ͢ΔPerlͷؔ਺ • fork & exec • redirect • pipe • ·ͱΊ

Slide 6

Slide 6 text

shellΛհ͢΂͔Βͣ • system "find $dir -type f -delete >/dev/null 2>&1"; • Ͳ͕͜໰୊ʁ • system΍execΛ1Ҿ਺Ͱ࣮ߦ͢ΔͱshellΛհ͠ ࣮ͯߦ͢ΔՄೳੑ͕͋Δɻ

Slide 7

Slide 7 text

shellΛհ͢΂͔Βͣ • ͍ΘΏΔshell injectionͷ͓ͦΕ͕͋Δɻ$dirʹ มͳจࣈ͍ΕΒΕͨΒʁ • ֎෦ϓϩάϥϜʹγάφϧૹͬͨͭ΋Γ͕shell ʹૹΔ͜ͱʹͳΔ • ۭനจࣈΛؚΉϑΝΠϧͰద੾ʹΫΦʔτ͠ͳ ͚Ε͹͍͚ͳ͍

Slide 8

Slide 8 text

shellΛհ͢΂͔Βͣ • shellΛىಈ͠ͳ͍ͷ͕Ұ൪ • ͍ΘΏΔinderectه๏Λ࢖͑͹Ͱ͖Δ

Slide 9

Slide 9 text

#!/usr/bin/env perl use strict; use warnings; system {"perl"} "perl", "-E", 'say "hello!"';

Slide 10

Slide 10 text

֎෦ϓϩάϥϜΛ࣮ߦ͢Δ
 Perlͷؔ਺ • ҎԼͷ4ͭ • system • ` ` (όοΫΫΦʔτ, qx) • fork & exec ← ࠓ೔͸͜Εʹ஫໨ • open (͜Ε͕Ұ൪PerlͬΆ͍!)

Slide 11

Slide 11 text

fork & exec • ࠓ೔͸fork & execͰ֎෦ϓϩάϥϜΛىಈͯ͠ ΈΔ • fork͸ࣗ෼ͷ෼਎Λ࡞ΔγεςϜίʔϧ • exec͸ࣗ෼ΛมԽͤ͞ΔγεςϜίʔϧ

Slide 12

Slide 12 text

#!/usr/bin/env perl use strict; use warnings; my $pid = fork // die; if ($pid == 0) { exec {"ls"} "ls", "-al"; exit 127; } wait; my $status = $?;

Slide 13

Slide 13 text

redirect • system "gzip —stdout out.txt"; • ίϚϯυͷग़ྗΛout.txt.gzʹ޲͚͍ͨɻ • system "gzip —stdout out.txt > out.txt.gz"; ͸ ΍Γͨ͘ͳ͍ɻ • open STDOUT, ">", "out.txt.gz" ͰͰ͖Δ

Slide 14

Slide 14 text

#!/usr/bin/env perl use strict; use warnings; my $pid = fork // die; if ($pid == 0) { open STDOUT, ">", "out.txt.gz"; exec {"gzip"} "gzip", "--stdout", "out.txt"; exit 127; } wait; my $status = $?;

Slide 15

Slide 15 text

pipe • ௕͘ଓ͘ϓϩάϥϜͷग़ྗʹ࣌ࠁΛ͚͍ͭͨɻ • pipeͰ֎෦ϓϩάϥϜͷग़ྗΛϦΞϧλΠϜʹ ड͚औΕ͹͍͍

Slide 16

Slide 16 text

#!/usr/bin/env perl use strict; use warnings; use POSIX 'strftime'; pipe my $stdout_read, my $stdout_write; my $pid = fork // die; if ($pid == 0) { close $stdout_read; open STDOUT, ">&=", $stdout_write; exec {"perl"} "perl", "-le", '$|++; for (1..10) { print $_; sleep 1 }'; } close $stdout_write; while (<$stdout_read>) { print strftime("%FT%T", localtime) . " $_"; } wait;

Slide 17

Slide 17 text

stderr΋औΓ͍ͨ

Slide 18

Slide 18 text

#!/usr/bin/env perl use strict; use warnings; use POSIX 'strftime'; pipe my $stdout_read, my $stdout_write; my $pid = fork // die; if ($pid == 0) { close $stdout_read; open STDOUT, ">&=", $stdout_write; open STDERR, ">&=", \*STDOUT; exec {"perl"} "perl", "-le", '$|++; for (1..10) { print $_; warn $_; sleep 1 }'; } close $stdout_write; while (<$stdout_read>) { print strftime("%FT%T", localtime) . " $_"; } wait; ϦμΠϨΫτ!

Slide 19

Slide 19 text

stdout/errผʑʹऔΓ ͍ͨ

Slide 20

Slide 20 text

#!/usr/bin/env perl use strict; use warnings; use POSIX 'strftime'; use IO::Select; pipe my $stdout_read, my $stdout_write; pipe my $stderr_read, my $stderr_write; my $pid = fork // die; if ($pid == 0) { close $stdout_read; close $stderr_read; open STDOUT, ">&=", $stdout_write; open STDERR, ">&=", $stderr_write; exec {"perl"} "perl", "-le", '$|++; for (1..10) { print $_; warn $_; sleep 1 }'; } close $stdout_write; close $stderr_write; my $select = IO::Select->new($stdout_read, $stderr_read); while ($select->count) { for my $fh ($select->can_read) { my $len = sysread $fh, my $str, 1024; if ($len) { my $type = $fh == $stdout_read ? "out": "err"; print strftime("%FT%T", localtime) . " $type $str"; } else { $select->remove($fh); close $fh; } } } wait; select!

Slide 21

Slide 21 text

·ͱΊ • ֎෦ϓϩάϥϜ࣮ߦͰ͸indirectه๏Λ࢖ͬͯ shellΛհ͞ͳ͍ͷ͕͍͍΍Γํ • open STDOUT, ">", "file.txt" ͰSTDOUTΛϑΝ ΠϧʹϦμΠϨΫτͰ͖Δ • pipeΛۦ࢖ͯ͠֎෦ϓϩάϥϜͱ௨৴Ͱ͖Δ

Slide 22

Slide 22 text

Further Reading • CPAN moduleΛಡΉͷ͕͓͢͢Ί • IPC::Run3, System::Command, Capture::Tiny • Proclet, Server::Starter