[ruby-list:49596] シェルスクリプトの Ruby での置き換え (was Re: コマンドラインで ruby の変数に値を設定する方法)
From:
尾川敏也 <ogw@...>
Date:
2013-09-21 23:24:46 UTC
List:
ruby-list #49596
尾川と申します。おはようございます。
1ケ月以上前のメールへのリプライで恐縮です。
UNIX Workstation (実際には現在は Cygwin) 上で、自作のフィルタプログ
ラムを sh や awk と組み合わせて使っているものを Ruby に置き換える件
の結果報告です。
頂いたアドバイス
in [ruby-list:49539] 中田さん wrote:
> それなりのボリュームがあるなら、全体をrubyスクリプトにしても
> いいかもしれません。
>
> #!/usr/local/bin/ruby -swnla
> BEGIN {
> datafile, $param = *ARGV
> $stdin.reopen(IO.popen("myprog1", "r", in: datafile))
> $stdout.reopen(IO.popen("myprog2", "w"))
> }
に触発されて色々勉強しまして、結局下記のようなやり方に落ち着きまし
た。
過去の資産を殆どそのまま機械的に Ruby に置き換えることができ、今後
は Cygwin 無しで済みそうです。
おまけに、従来 awk で書いていた部分は、その気になれば Ruby で非常に
すっきりとコンパクトに書けるようにもなりました。
ちょっと幸せな気分です。あらためて、ありがとうございました。
それにしても、Ruby は楽しいですね。
*****
myprog1, myprog2, myprog3 は C で書いた外部のフィルタプログラムで、
シェルスクリプトが例えば:
----------------- mytest.sh ------------------------
myprog1 datafile.txt |
myprog2 |
awk '{
#
# awk による行毎のちょっとした処理
# 結果は標準出力に書き出す
#
print foo
}' |
myprog3 -a -b > result.txt
----------------------------------------------------
だったとして、これを Ruby では以下のように書けるようになりました。
意味的な見た目も含めてほぼ1対1であるため、元のシェルスクリプトを
コピーして行毎に少し書き直すだけで簡単に Ruby に置き換えられます。
----------------- mytest.rb ------------------------
require_relative "mylib"
"".
|("myprog1 datafile.txt").
|("myprog2").
byline do |sio, n, str|
#
# Ruby による行毎のちょっとした処理
# 結果は StringIO の sio に書き出す
#
sio.puts foo
end.
|("myprog3 -a -b").v("result.txt")
----------------------------------------------------
require している mylib は、String をモンキーパッチング(と言うので
しょうか?)して、メソッド '|', 'byline', 'v' を追加している自作の
ライブラリで、内容は:
----------------- mylib.rb -------------------------
require "stringio"
class String
# パイプ | を模擬した外部コマンドの実行
def |(cmdline)
IO.popen(cmdline, "w+") do |pipe|
Thread.fork { # write のブロック防止
pipe.write self
pipe.close_write # read のブロック防止
}
pipe.read
end
end
# リダイレクト > を v で模擬
def v(filename)
File.open(filename, "w") do |f|
f.puts self
end
self
end
# 行単位で処理した結果全体をまとめて返すイタレータ
def byline
result = ""
sio = StringIO.new result
n = 0 # 入力行番号
self.each_line do |str|
n += 1
yield sio, n, str
end
sio.close
result # 各行の処理結果をまとめて返す
end
end
----------------------------------------------------
以上です。
--
尾川敏也 ogw@shizuokanet.ne.jp
http://www6.shizuokanet.ne.jp/ogw/