More Related Content
Similar to Ruby での外部コマンドの実行について (20)
More from Tomoya Kawanishi (20)
Ruby での外部コマンドの実行について
- 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. 大手町.rb #16 「Ruby での外部コマンドの実行について」
今日のテーマ
Ruby での外部コマンドの実行について
外部コマンド
ruby では system コマンド
echo 、time、ruby などすべて外部コマンド
Ruby はグルー言語としてとても優秀
グルー = のり(糊)
いろんな処理をくっつけて、新しい処理を組み立てるときに
使う言語を グルー言語 と呼ぶ
すでにいろんなベンリな機能がたくさんあるわけだし、
グルー言語として、実現する方がカンタンかつ速い!
2
- 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. 大手町.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. 大手町.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. 大手町.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. 大手町.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. 大手町.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. 大手町.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. 大手町.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. 大手町.rb #16 「Ruby での外部コマンドの実行について」
まとめ
Ruby での外部コマンドの実行方法についていろいろ紹介
しました
開発生産性を改善するには
・あるものは使う。つなぐ
というのが大切です
Rubyはいろんなライブラリが用意されているので
どんな状況でもたいてい自動化することができます
今日の説明が今後の開発にお役立ちできるとうれしいです
11