Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Ruby での外部コマンドの実行について

894 views

Published on

大手町.rb #16発表資料

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Ruby での外部コマンドの実行について

  1. 1. Ruby での 外部コマンドの実行について 2019/04/10 大手町.rb #16
  2. 2. 大手町.rb #16 「Ruby での外部コマンドの実行について」 1自己紹介 Tomoya Kawanishi a.k.a. @cuzic エネチェンジ株式会社 チーフエンジニア 電力会社、ガス会社を切り替えるなら、エネチェンジ経由で! 一般家庭も!法人も! Ruby関西の中の人 2019年5月11日 第86回Ruby関西勉強会 2019年7月13日 第87回Ruby関西勉強会 発表者として登壇くださる方、あとで声かけください。 大手町.rb の中の人 毎月 大手町.rb の開催を予定 東京駅、各線大手町駅から直結! Ruby の初級者がメインターゲット
  3. 3. 大手町.rb #16 「Ruby での外部コマンドの実行について」 今日のテーマ Ruby での外部コマンドの実行について 外部コマンド ruby では system コマンド echo 、time、ruby などすべて外部コマンド Ruby はグルー言語としてとても優秀 グルー = のり(糊) いろんな処理をくっつけて、新しい処理を組み立てるときに 使う言語を グルー言語 と呼ぶ すでにいろんなベンリな機能がたくさんあるわけだし、 グルー言語として、実現する方がカンタンかつ速い! 2
  4. 4. 大手町.rb #16 「Ruby での外部コマンドの実行について」 ` ` (backtick)、 %x()、%X() `` 、%x で簡単に外部コマンドの実行結果が取得可能 3 `aws configure get aws_access_key_id`.chomp #=> "AKIA...........A" `git config user.name`.chomp #=> "cuzic" # `` と %x は式展開する field = "user.name" `echo #{field}"`.chomp #=> "user.name" %x(echo #{field}").chomp #=> "user.name" # %X だと式展開しない %X(echo #{field}").chomp #=> "#{field}"
  5. 5. 大手町.rb #16 「Ruby での外部コマンドの実行について」 Kernel.system 外部コマンドを実行し、成功したときに真が返る 4 system("echo Hello, World!") # PATH で見つかる echo を呼ぶ system("echo /dev/z*") # ワイルドカードも書ける。シェル経由で実行される。 system('echo –n a¥nb') # /bin/echo は bash の echo と挙動が異なる。 # 成功するときは、true が返る system("true") #=> true # 失敗するときは false が返る system("false") #=> false # ; 区切りで複数コマンド実行できる system("echo 1 ; echo 2") # 改行区切りでも複数コマンド実行できる system("echo 1 ¥n echo 2") # 該当のコマンドが実行できないときは nil が返る system("sad") #=> nil
  6. 6. 大手町.rb #16 「Ruby での外部コマンドの実行について」 system の高度な利用 5 # 配列で引数を渡すこともできる system("ssh", hostname, "bash –l –c 'cd repo; bin/rails c'") # exception: true を指定すると、 nil が返るのではなく例外を raiseする system("sad", exception: true) #=> Errno::ENOENT (No such file or directory - sad) # unsetenv_others: true を指定すると、環境変数をクリアする system("echo $HOME") # "/home/cuzic" などが表示される system("echo $HOME", unsetenv_others: true) # 何も表示されない # bundle exec の中で ruby コマンドを実行するときとか便利 # 第1引数で環境変数を指定できる system({"FOO"=>"BAR"}, "echo $FOO") # chdir オプションで子プロセスのカレントディレクトリを変更できる # "cd /tmp; pwd" とすると、シェル経由で実行されるが、 # 下記はシェルを経由せず、実行される system("pwd", chdir: "/tmp")
  7. 7. 大手町.rb #16 「Ruby での外部コマンドの実行について」 Kernel.exec exec で実行すると ruby インタプリタを置き換える ruby で ssh を wrap したい時とかベンリ 6 STDIN.close STDOUT.close system("ssh production-server") # `system': closed stream (IOError) STDIN.close STDOUT.close exec("ssh production-server") # ふつうに ssh できる! system("ssh production-server") puts "ssh finished" # ssh 終了後、実行、表示される exec("ssh production-server") puts "ssh finished" # ssh 終了してもこの行は決して実行されない
  8. 8. 大手町.rb #16 「Ruby での外部コマンドの実行について」 shellwords Array#shelljoin 、String#shellescape がベンリ 7 # system メソッドに配列で引数を渡す system("ssh", hostname, "bash –l –c 'cd repo; bin/rails version'") # String#shellescape rails_version = "bash –l –c 'cd repo; bin/rails version'" require 'shellwords' rails_version.shellescape #=> "bash¥¥ ¥¥–l¥¥ ¥¥–c¥¥ ¥¥'cd¥¥ repo¥¥;¥¥ bin/rails¥¥ version¥¥'" # Array#shelljoin cmdline = ["ssh", hostname, rails_version].shelljoin #=> "ssh production-server bash¥¥ ¥¥–l¥¥ ¥¥–c¥¥ ¥¥'cd¥¥ repo¥¥;¥¥ bin/rails¥¥ version¥¥'" # system メソッドに文字列で渡す `#{cmdline}` #=> "Rails 5.0.7¥n"
  9. 9. 大手町.rb #16 「Ruby での外部コマンドの実行について」 IO.popen IO.popen で、標準入力からの値の取得ができる エンコーディングの指定もできる 標準エラー出力も受け取れる 8 env = {"PGUSER"=>"scott", "PGPASSWORD"=>"tiger"} body = IO.popen(env, "psql template1", "r+") do |io| io.puts '¥dS+' io.close_write io.read end puts body IO.popen("nkf –s README.md", external_encoding: "CP932", &:read) IO.popen("ls /nothing", err: %i(child out), &:read) #=> "ls: /nothing にアクセスできません: そのようなファイルやディレクトリはあり ません¥n"
  10. 10. 大手町.rb #16 「Ruby での外部コマンドの実行について」 Open3.capture3 標準入力への入力、標準出力、標準エラー出力の取得が 一度にできてとてもベンリ! 環境変数の設定などもできる 9 require 'open3' env = {"PGUSER"=>"scott", "PGPASSWORD"=>"tiger"} sql = <<'EOD' ¥d selct 1 + 1; EOD options = {stdin_data: sql} o, e, s = Open3.capture3(env, "psql", "template1", options) p o #=> "リレーションがありません。¥n" p e #=> "ERROR: ¥"selct¥"またはその近辺で構文エラー¥n行 1:" p s #=> #<Process::Status: pid 21358 exit 0> select を typo してる!
  11. 11. 大手町.rb #16 「Ruby での外部コマンドの実行について」 expect PTY と expect でインタラクティブ操作も自動化できる 非常に多数の L2SW やルータを自動制御したいときとか便利 10 require 'pty' require 'expect' username, password, database = "scott", "tiger", "template1" PTY.getpty("psql –U #{username} #{database}") do |i, o| o.sync = true i.expect(/パスワード:/) do o.puts password i.expect(/#{database}/) do o.puts "¥¥d" i.expect(/#{database}/) do |result| puts result end end end end
  12. 12. 大手町.rb #16 「Ruby での外部コマンドの実行について」 まとめ Ruby での外部コマンドの実行方法についていろいろ紹介 しました 開発生産性を改善するには ・あるものは使う。つなぐ というのが大切です Rubyはいろんなライブラリが用意されているので どんな状況でもたいてい自動化することができます 今日の説明が今後の開発にお役立ちできるとうれしいです 11
  13. 13. ご清聴ありがとう ございました

×