TransWikia.com

Unixのパイプラインで透過的にふるまうRubyのスクリプトを作るには?

スタック・オーバーフロー Asked by kojix2 on February 18, 2021

こんにちは。標準ストリームについての質問です。
Unixのパイプラインで使用して、透過的に使うツールを作りたいと考えています。(透過的という用語をこの文脈で使っていいのかどうかわかりませんが、具体的には tee のようなものを想定しています。)

下記のようなスクリプト pass.rb を作成したとして

#! /usr/bin/env ruby

lines = readlines.map(&:chomp)

# do something useful...
#   
# end

puts lines

chmod +x pass.rb

この pass.rb はパイプの中間に挟んだ時に

hoge | ./pass.rb | fuga
hoge | fuga

fugaに渡される入力データは常に同じになるでしょうか?

もし同等にならない場合は、どのような例で問題が発生するのか、
どうすれば同等にできるのかを教えて頂けると助かります。

よろしくおねがいします。

3 Answers

chomp しているので、入力されたデータの改行コードが変わる可能性があります。

たとえば改行コードのデフォルトが LF の環境において改行コードが CRLF の入力を食わせると、出力の改行コードが LF になってしまいます。

% cat foo.txt | od -c
0000000    a   a   a  r  n                                            
0000005
% cat foo.txt | ./pass.rb | od -c
0000000    a   a   a  n                                                
0000004

パイプからテキスト以外のデータが流れてくる可能性も考えると、入出力部分ではバイナリデータとして読み書きし、"do something useful" 部分で必要に応じてテキストデータに変換するのが良さそうです。

Correct answer by nekketsuuu on February 18, 2021

次のようにしました。

#! /usr/bin/env ruby

while = Kernel.gets(nil)
  input.freeze # 変更されないようにする

  # 処理

  print input
end

Answered by kojix2 on February 18, 2021

パイプの中間に pass.rb を挟んだ時に
fugaに渡される入力データは常に同じになるでしょうか?
もし同等にならない場合は、どのような例で問題が発生するのか

nekketsuuuさんの回答のとおり、NGとなるケースがあるようです。

どうすれば同等にできるのかを教えて頂けると助かります。

rubyに詳しくないので、見当違いかもしれませんが、あらゆるケースを想定するなら、バイナリとして読み込み、バイナリとして書き込む方法しか思いつきません。


次の方法を使えば、お望みのことが実現できると思います。かなり邪道です。
標準エラー出力を本来とは異なる用途で使っているので、実務に使うのは危険です。
エラーメッセージがスクリプトに処理されたり、表示されなくなったりするからです。
なお、teeコマンドとbashのcoprocを使っています。

やり方は以下のとおりです。
1)coprocでスクリプトを起動します。※例えばpass.rb
2)teeを使って標準入力を標準エラー出力デバイスファイルに流します。
3)teeの標準出力はcoprocで起動したスクリプトの標準入力に書き込みます。
4)標準エラー出力を標準出力に戻します。

以下のように実行します。スクリプトはpeep.shとしています。

hoge | ./peep.sh スクリプト | fuga

peep.shの内容

#!/bin/bash
prc=$1
coproc cprc { ${prc}; }
{
    tee -p /dev/stderr >&${cprc[1]}

} 2>&1

Answered by akira ejiri on February 18, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP