0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rubyで標準入出力がリダイレクトされてもリダイレクトされていない時と同じように動いてほしい

Last updated at Posted at 2023-11-13

はじめに

本題に至るまでに疲れて脱落者が出そうなので、はじめにお断りです。

Rubyでの\$stdinや\$stdoutの使い方の話ですよ!

では、始めましょう。

背景

最近Macを更新しました。接続規格が大幅に変わっているので、周辺機器が軒並み繋がらないのは覚悟していたのですが、「流石にこれは大丈夫ではないか」と思っていたバーコードリーダーも使えなくなってしまいました。バーコードリーダーはキーボードの振りをするのですが、最近のMacでは「そんな怪しいキーボードは使わせない」ということなのか接続されたことは認識するもののそれ以上は進みません。(おそらくセキュリティ強化のためなのでしょう。そういう時代ですよね、、、)
そこで「パンがなければお菓子を食べればいい」ということで、以下のように回避することにしました。

  1. バーコードリーダーをFreeBSD(GhostBSD)に接続1。FreeBSDはUSBキーボードだと思ってくれるので、問題なく動作します。
  2. FreeBSDで入力された値をネットワーク経由でMacに送信。
  3. Macで受信したデータを標準出力に表示。
  4. 今までコンソールで受け取っていたものの代わりに標準出力に表示されたものをデータとして受け取るように。

バーコードリーダーやFreeBSD(GhostBSD)は逸般の誤家庭にあるものをお使いください。

ネットワーク通信(受信)の準備

ネットワークでデータを受信するプログラムはこんな感じでしょう。

receiver.rb
抜粋です
gs = TCPServer.open(port)
s = gs.accept
while a = s.gets
  print a
end
s.close

注意!!!

背景の内容から推測はつくと思いますが、データの送信側も受信側も自分の目の前にある(当然自分の目が行き届いている)というのが前提です。これを何も考えずにインターネット上でやって問題が起きても責任は負えません。

本題

ようやく本題です。以前は以下のようなプログラムでバーコードリーダーからのデータを受け取っていました。

input.rb
抜粋です
f = IO::console
print "ISBN: "
until f.eof
  t_isbn = f.readline.chomp
以下略

さて、receiver.rbを単体で動かすと「Macで受信したデータを標準出力に表示」ができていることが確認できました。

ruby receiver.rb | ruby input.rb 

で期待通り動作するといいですね。実際にやってみます。
、、、???input.rbがずっと入力待ちのままです。

(半分)解決

そう言えば

f = IO::console

とコンソールから明示的に入力を受け付けるように書いてましたね。これでは動かないはずです。以下のように書き換えます。(もっと良い方法があるかも知れませんが、既存のスクリプトの書き換えが一番少なそうな方法なので、これで。)

f = $stdin

再挑戦します。データは確かに届きます。届くのですが、実際にバーコードリーダーを使っている時には何もデータは来なくて、FreeBSD側でネットワークを切断するとドドドっと来ます。
、、、そうじゃない!!!今までMacにバーコードリーダーを直接接続していた時みたいに動いてほしいんです。

(残り半分)解決

解決に至るまで紆余曲折がありましたが、結果だけ書きます。
receiver.rbの初めの方で

$stdout.sync = true

と書けばよいです。
Rubyで標準出力を利用する機能は、標準出力先が「普通の」標準出力なのかそうでない(パイプとかリダイレクトとか)のかを把握して、それに応じて動作を変えているようです。上の設定は、「そういうのは気にしなくていいから、同期的に動いてね」という意味でしょう。

ruby receiver.rb | ruby input.rb 

で期待通り動作しました。

おまけ

データの入力自体はうまくいっているのですが、バーコードリーダーが読み取った値はFreeBSD側の画面に表示されているだけで、Mac側には"ISBN: "とかの表示だけが流れていくだけです。これで妥協してもよかったのですが、「あとちょっとの労力」ということでMacでも表示されるようにしました。具体的には以下の2行目を追加です。

  t_isbn = f.readline.chomp
  puts t_isbn if not $stdin.tty?

これで画面表示も含めてそっくりになりました。めでたし、めでたし。

おことわりなど

恒例のお断りですが、この文章の内容は、筆者が所属している会社・団体とは一切関わりがありません。いわゆる「自主的な研究の成果の発表」というものです。

え、タイトルが「リダイレクト」なのに書いてある内容は「パイプ」なのでは?ですか。その通りですけど、こまけぇこたぁいいんだよ!!

  1. ちょっとここは省略し過ぎたのかもしれませんが「FreeBSDは仮想マシン上で動作しているのですか」と聞かれました。うーん、そういう時代なのかもしれませんね。だがしかし、だーかーらー、そもそもMacがハードウェアを認識しないのだから、Mac上の仮想マシンでOSを変わったのを使ったところで無駄でしょ!逸般の誤家庭なら当然実機です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?