LoginSignup
3
2

More than 5 years have passed since last update.

cutコマンドでバッファリングさせないようにする

Last updated at Posted at 2018-02-19

USBでMacに繋ぐとシリアルデバイスとして認識される温度湿度気圧センサがあるとします。
このセンサは1秒に1回 20.00,10.00,1000.00 という形式のデータを送ってきます。
20.00が温度、10.00が湿度、1000.00が気圧です。
手元にセンサがない人もいることでしょうし、センサのかわりに以下のようなスクリプトを用意します。

sensor.sh
#!/bin/sh
while :; do
  echo 20.00,10.00,1000.00
  sleep 1
done

これを実行すると、以下のように1秒ごとにデータが流れてきます。

$ ./sensor.sh 
20.00,10.00,1000.00
20.00,10.00,1000.00
20.00,10.00,1000.00
20.00,10.00,1000.00
20.00,10.00,1000.00
.
.
.

温度だけ取り出したいので、cutコマンドを使ってみます。

./sensor.sh | cut -d, -f1
20.00
20.00
20.00
.
.
.

うまくいきました。

今度は温度をコンソール上で確認しながら同時にファイルに記録しておきたいので、teeに渡してみます。

$ ./sensor.sh | cut -d, -f1 | tee temp

あれれ、なにも出てきません。tempの中身も空っぽです。
どうやら、端末以外に出力するときは、cutが標準出力をバッファリングするみたいです。

cut bufferingなどでGoogleで検索すると、stdbufというコマンドを使うとバッファリングなしを強制できるようです。
ところがstdbufはGNUとBSDでともに提供されているものの、macOSにははいっていません。これはちょっとめんどくさいです。

いろいろ悩んだ挙句、whilereadを使えばPOSIXの範疇で簡単に解決できることに気づきました。

$ ./sensor.sh | while read l; do echo $l | cut -d, -f1; done | tee temp
20.00
20.00
20.00
20.00
20.00
^C
$ cat temp 
20.00
20.00
20.00
20.00
20.00

1秒ごとに20.00が表示されます。うまくいきました。

ワンライナーだと見づらいのでシェルスクリプトとして書いてみます。

./sensor.sh         |
cut -d, -f1         |
while read line; do
  echo ${line} |
  cut -d',' -f1
done                |
tee temp

タイトルに反して「バッファリングさせないようにしている」わけではないですが、ラインバッファを強制したときと同じ結果が得られました。
cutを毎回起動するのでパフォーマンスの面では劣りますが、POSIXの範囲内で簡単に解決できたのと、元々多くても1秒間隔くらいでやってくるデータを想定しているので、これでじゅうぶんだと思います。
cutに限らず、awkなど出力をバッファリングしてしまうコマンドに出くわしたときに使える手だと思います。

3
2
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
3
2