2015-06-28

Makefile: Here document

Makefile にターゲットを色々詰め込んでいくと、ターゲットの一覧をヘルプで表示させたくなる。そのようなターゲット「help」を作るのは簡単だが、毎行 echo するとか毎行末 \ エスケープするとか面倒なことはやりたくない。そうなると、じゃあヒアドキュメントはできないの?ってなるが、Makefile 文法とヒアドキュメント文法の相性が悪すぎて正攻法ではどうにもならない。というか私には無理だった。

環境変数を使え、と。なるほど、make に文字列を展開させるのではなく、シェルに実行時展開させれば良いのか。そうすれば make による文法解析を回避できる。

Makefile:

export _help_msg
override define _help_msg
Targets:
  compile    Compile and build sources.
  install    Install into the PREFIX.
  uninstall  Uninstall the installed files.
  clean      Remove all generated files.
  help       This message.
Variables:
  PREFIX     The path to be installed.
endef

help:
	@echo "$$_help_msg"

compile:
install:
uninstall:
clean:
# make help
Targets:
  compile    Compile and build sources.
  install    Install into the PREFIX.
  uninstall  Uninstall the installed files.
  clean      Remove all generated files.
  help       This message.
Variables:
  PREFIX     The path to be installed.

ただし、この方法は環境変数を export するので子プロセスに影響を与える可能性が残るのが少し気持ち悪い。あとエディターによっては(Emacs とか)、行中に半端なクォート(「'」「"」)があると色付けが破綻する。まあ毎行 echo するよりはマシ、ということで妥協するしかないか。

2015-05-21

RHEL7: Set RTC to local time

ようやく RHEL7 を触り始めたので、その辺の話題を。

RHEL7 をインストールした日本人が最初に困るであろうことの 1 つが、OS 時刻がずれていること。これは RTC (要は BIOS 時刻)が UTC と扱われることが原因。RHEL6 まではインストール時に UTC にするかどうか選択できていたのに、RHEL7 では問答無用で UTC になる。

[rhel7]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)

[rhel7]# timedatectl status
      Local time: Fri 2015-05-22 02:04:00 JST
  Universal time: Thu 2015-05-21 17:04:00 UTC
        RTC time: Thu 2015-05-21 17:04:00
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

[rhel7]# cat /etc/adjtime
0.0 0 0.0
0
UTC

上記で RTC 時刻は日本時刻に合っているが、OS 時刻はそれより 9 時間進んでいる。

まあこれは FAQ なので、ググればすぐに「timedatectl set-local-rtc 1」すれば良いことは分かるし、公式ドキュメントにも記載がある。

[rhel7]# timedatectl set-local-rtc 1

[rhel7]# timedatectl status
      Local time: Fri 2015-05-22 02:04:49 JST
  Universal time: Thu 2015-05-21 17:04:49 UTC
        RTC time: Fri 2015-05-22 02:04:50
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: yes
      DST active: n/a

Warning: The RTC is configured to maintain time in the local timezone. This
         mode is not fully supported and will create various problems with time
         zone changes and daylight saving adjustments. If at all possible use
         RTC in UTC, by calling 'timedatectl set-local-rtc 0'.

[rhel7]# cat /etc/adjtime
0.0 0 0.0
0
LOCAL

これで確かに RTC は local time になる。しかし OS 時刻は進んだままだし、今度は RTC 時刻までもが進んでしまった。恐らくこれは皆が望む結果ではない。少なくとも私は望まない。これを私が望む結果にするには、set-local-rtc 時にオプション --adjust-system-clock を使う。(詳しくは、man timedatectl)

[rhel7]# timedatectl status
      Local time: Sat 2015-05-23 02:09:00 JST
  Universal time: Fri 2015-05-22 17:09:00 UTC
        RTC time: Fri 2015-05-22 17:09:00
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

[rhel7]# cat /etc/adjtime
0.0 0 0.0
0
UTC

[rhel7]# timedatectl set-local-rtc 1 --adjust-system-clock

[rhel7]# timedatectl status
      Local time: Fri 2015-05-22 17:11:04 JST
  Universal time: Fri 2015-05-22 08:11:04 UTC
        RTC time: Fri 2015-05-22 17:11:04
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: yes
      DST active: n/a

Warning: The RTC is configured to maintain time in the local timezone. This
         mode is not fully supported and will create various problems with time
         zone changes and daylight saving adjustments. If at all possible use
         RTC in UTC, by calling 'timedatectl set-local-rtc 0'.

[rhel7]# cat /etc/adjtime
0.0 0 0.0
0
LOCAL

これで私が望む結果になった。まあ普通の人は「set-local-rtc した後で時刻を合わせ直すから問題ない」で終了しそうだが。

ところで RTC を local time にすると、上記のようにいちいち Warning が出るようになる。言っていることは分かるが、UTC にすると BIOS 時刻がずれてしまうのが気持ち悪い。

例えばインターネットに繋がっている環境では自動的に時刻同期するので、何も意識せずに RHEL7 を使っている人も多いと思う。そういうシステムでは多分このようになっている。

[rhel7]# timedatectl status
      Local time: Thu 2015-05-21 17:17:31 JST
  Universal time: Thu 2015-05-21 08:17:31 UTC
        RTC time: Thu 2015-05-21 08:17:31
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a

OS 時刻は日本時間に合っているが、RTC 時刻は(UTC なので) 9 時間遅れている。システム管理者とは別の SE がハードウェア保守をやっている場合、「毎回 BIOS 時刻を直しているのにまた狂った。このサーバーは変だ!」と騒ぎ出すかも知れない。それ以前、大抵は RHEL7 を使っている当人でさえ、BIOS 時刻を見る度に「?」ってなるだろう。

ちなみに RHEL5 / RHEL6 では、UTC を local time にするのに下記を使っていた。昔のことなのであまり覚えていないが、当時も私が望む結果にするため、色々と調べた記憶はある。

if grep '^UTC$' /etc/adjtime ; then
    hwclock --hctosys --local && hwclock --adjust --local
fi

これはそのまま RHEL7 でも動くが、変更結果を timedatectl コマンドの方に反映させるには、systemd-timedated を再起動する必要がある。


2015-08-13 追記

ということで、私としては一件落着したつもりだった。ところが!

RTC を local time にすると、OS 起動時に ログのタイムスタンプがずれる ことに気が付いた。

次のように local time になっている状態で、OS を再起動してみる。

[rhel7]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)

[rhel7]# timedatectl
      Local time: Thu 2015-08-13 11:47:46 JST
  Universal time: Thu 2015-08-13 02:47:46 UTC
        RTC time: Thu 2015-08-13 11:47:46
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: yes
      DST active: n/a

Warning: The RTC is configured to maintain time in the local timezone. This
         mode is not fully supported and will create various problems with time
         zone changes and daylight saving adjustments. If at all possible use
         RTC in UTC, by calling 'timedatectl set-local-rtc 0'.

[rhel7]# reboot

その時の /var/log/messages の抜粋。

Aug 13 11:48:25 rhel7 systemd: Stopping user-0.slice.
Aug 13 11:48:25 rhel7 systemd: Removed slice user-0.slice.
Aug 13 11:48:25 rhel7 systemd: Stopping Dump dmesg to /var/log/dmesg...
Aug 13 11:48:25 rhel7 rsyslogd: [origin software="rsyslogd" swVersion="7.4.7" x-pid="486" x-info="http://www.rsyslog.com"] exiting on signal 15.
Aug 13 11:48:42 rhel7 rsyslogd: [origin software="rsyslogd" swVersion="7.4.7" x-pid="486" x-info="http://www.rsyslog.com"] start
Aug 13 20:48:34 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.1M, current limit 37.0M).
Aug 13 20:48:34 rhel7 kernel: Initializing cgroup subsys cpuset
Aug 13 20:48:34 rhel7 kernel: Initializing cgroup subsys cpu
Aug 13 20:48:34 rhel7 kernel: Initializing cgroup subsys cpuacct
Aug 13 20:48:34 rhel7 kernel: Linux version 3.10.0-229.el7.x86_64 (mockbuild@x86-035.build.eng.bos.redhat.com) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC) ) #1 SMP Thu Jan 29 18:37:38 EST 2015
Aug 13 20:48:34 rhel7 kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-229.el7.x86_64 root=UUID=7aa3d286-206c-4938-82ce-cfbc6635c417 ro crashkernel=auto rhgb quiet LANG=ja_JP.UTF-8
<...snip...>
Aug 13 20:48:36 rhel7 systemd: Starting Switch Root.
Aug 13 20:48:36 rhel7 systemd: Reached target Switch Root.
Aug 13 20:48:36 rhel7 systemd: Started Plymouth switch root service.
Aug 13 20:48:36 rhel7 systemd: Starting Switch Root...
Aug 13 20:48:36 rhel7 systemd: Switching root.
Aug 13 20:48:36 rhel7 journal: Journal stopped
Aug 13 11:48:38 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.0M, current limit 37.0M).
Aug 13 11:48:38 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.0M, current limit 37.0M).
Aug 13 11:48:38 rhel7 systemd-journald[90]: Received SIGTERM
Aug 13 11:48:38 rhel7 kernel: type=1404 audit(1439466516.972:2): enforcing=1 old_enforcing=0 auid=4294967295 ses=4294967295
Aug 13 11:48:38 rhel7 kernel: type=1403 audit(1439466517.276:3): policy loaded auid=4294967295 ses=4294967295
Aug 13 11:48:38 rhel7 systemd[1]: Successfully loaded SELinux policy in 322.882ms.
Aug 13 11:48:38 rhel7 systemd[1]: RTC configured in localtime, applying delta of 540 minutes to system time.
Aug 13 11:48:38 rhel7 systemd[1]: Relabelled /dev and /run in 39.287ms.
Aug 13 11:48:38 rhel7 journal: Journal started
Aug 13 11:48:38 rhel7 systemd: systemd 208 running in system mode. (+PAM +LIBWRAP +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)

ある期間だけ、タイムスタンプがずれている。前後関係から、rsyslogd が落ちている間に journald が溜め込んだログのように見える。9 時間戻る(UTC 時刻になる)のならともかく、9 時間進むというのは良く分からない。

一方、RTC が UTC の場合、

[rhel7]# timedatectl
      Local time: Thu 2015-08-13 11:51:56 JST
  Universal time: Thu 2015-08-13 02:51:56 UTC
        RTC time: Thu 2015-08-13 02:51:57
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

[rhel7]# reboot

今度はタイムスタンプはずれない。(正確には、ちょっとずれるけど大きくはずれない)

Aug 13 11:52:14 rhel7 systemd: Stopping user-0.slice.
Aug 13 11:52:14 rhel7 systemd: Removed slice user-0.slice.
Aug 13 11:52:14 rhel7 systemd: Stopping Dump dmesg to /var/log/dmesg...
Aug 13 11:52:14 rhel7 systemd: Stopped Dump dmesg to /var/log/dmesg.
Aug 13 11:52:14 rhel7 systemd: Stopping Multi-User System.
Aug 13 11:52:14 rhel7 systemd: Stopped target Multi-User System.
Aug 13 11:52:14 rhel7 systemd: Stopping Command Scheduler...
Aug 13 11:52:14 rhel7 rsyslogd: [origin software="rsyslogd" swVersion="7.4.7" x-pid="486" x-info="http://www.rsyslog.com"] exiting on signal 15.
Aug 13 11:52:30 rhel7 rsyslogd: [origin software="rsyslogd" swVersion="7.4.7" x-pid="487" x-info="http://www.rsyslog.com"] start
Aug 13 11:52:23 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.1M, current limit 37.0M).
Aug 13 11:52:23 rhel7 kernel: Initializing cgroup subsys cpuset
Aug 13 11:52:23 rhel7 kernel: Initializing cgroup subsys cpu
Aug 13 11:52:23 rhel7 kernel: Initializing cgroup subsys cpuacct
Aug 13 11:52:23 rhel7 kernel: Linux version 3.10.0-229.el7.x86_64 (mockbuild@x86-035.build.eng.bos.redhat.com) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC) ) #1 SMP Thu Jan 29 18:37:38 EST 2015
Aug 13 11:52:23 rhel7 kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-229.el7.x86_64 root=UUID=7aa3d286-206c-4938-82ce-cfbc6635c417 ro crashkernel=auto rhgb quiet LANG=ja_JP.UTF-8
<...snip...>
Aug 13 11:52:25 rhel7 systemd: Starting Switch Root.
Aug 13 11:52:25 rhel7 systemd: Reached target Switch Root.
Aug 13 11:52:25 rhel7 systemd: Started Plymouth switch root service.
Aug 13 11:52:25 rhel7 systemd: Starting Switch Root...
Aug 13 11:52:25 rhel7 systemd: Switching root.
Aug 13 11:52:25 rhel7 journal: Journal stopped
Aug 13 11:52:27 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.0M, current limit 37.0M).
Aug 13 11:52:27 rhel7 journal: Runtime journal is using 4.6M (max 37.0M, leaving 55.6M of free 366.0M, current limit 37.0M).
Aug 13 11:52:27 rhel7 systemd-journald[90]: Received SIGTERM
Aug 13 11:52:27 rhel7 kernel: type=1404 audit(1439434345.778:2): enforcing=1 old_enforcing=0 auid=4294967295 ses=4294967295
Aug 13 11:52:27 rhel7 kernel: type=1403 audit(1439434346.070:3): policy loaded auid=4294967295 ses=4294967295
Aug 13 11:52:27 rhel7 systemd[1]: Successfully loaded SELinux policy in 307.437ms.
Aug 13 11:52:27 rhel7 systemd[1]: Relabelled /dev and /run in 39.670ms.
Aug 13 11:52:27 rhel7 journal: Journal started
Aug 13 11:52:27 rhel7 systemd: systemd 208 running in system mode. (+PAM +LIBWRAP +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)

OS 起動時だけとはいえ、ログのタイムスタンプがずれることを許容したくない場合はあるだろう。その場合、RTC は UTC にしておく必要がある。

実際 RHEL7 を触っていると、今回みたく酷いものでなくても、RTC が UTC であることを前提としている印象を受けることがある。今までは私も「そうは言ってもねえ、」とそれに抗っていたが、今回の件でスッパリと諦めた。正直、他にどういう副作用があるか知れない。なので現時点での結論は、

RHEL7 で余計な面倒に遭いたくないなら、RTC は UTC にしとけ。

後は、BIOS 時刻(9 時間遅れている)を見た人が、時刻を直して くれない ことを祈るのみ。

2015-04-30

Animes in the 1st quarter of 2015

アニメは IT エンジニアの必須科目です。 ということで簡単なレビューを。

いわく「バクマン。」のアニメ制作版。アニメ制作にこれだけの役職が本当に必要なのか疑問が残るが、勉強にはなった。で、やはりアニメは見る側に限る、との結論。

一見すると NHK がやってそうな作品。ギャグも多くヒロインも魅力的だが、何かもう一押し物足りない気がする。ともあれ、次回にも期待。

メカ良し、キャラもなかなか、声優も有名どころを揃えている。それでもつまらないのが昨今のサンライズクオリティ。ところでエンド後ってタスクしか種馬いなくね?

前作より視聴。相変わらず、気持ち偏重の展開。安心しては見られるが、楽しめば結果がついてくる、というのは本格的なスポーツ作品としては安易に思える。

人気漫画とのことで興味があったが、主人公が分かり易くて先が読める。むしろ野球に対する姿勢では古谷の方が好ましい。あと、続けて次期をやる意味が分からない。

話に深みは無さそうだと見ていたら、「俺は~強い」の種明かしには感心した。あと長引かせずに 2 クールで一旦終わらせたのも賢明だと思う。某海賊も見習えと言いたい。

原作は既読。早過ぎるアニメ化だと思ったら、原作も一緒に終わって納得。丁寧な作りで音にも拘っているようだが、やはり原作を読みたい。音への拘りは素人(私)には分からないし。

三期目らしいので、どんな物かと視聴。結果、「獣っ娘」需要と判断。話は仲良しごっこの温い内容で、良く言えば安心して見られる。しかしもう次回は見ないと思う。

原作を知らないのでキャラが多過ぎる。各キャラも全然掘り下げられていないし、これを 1 クールでやるのは無理だったと思う。あとプロデューサーがキモい。

暫く見て ED 絵のセンスがいいなと思ってから、実は作品を通してセンスが良いのではと思えてきた。惜しむらくは地味なこと。で最後、結局ちーちゃんは帰ってきたの? こなかったの? そこが気になる。

名前からして嫌な予感しかしないが、「ガッチャマンクラウズ」の例もあるのでスルーもできない。結果は玉砕。ドクロベエの中の人が現役だったのがうれしかったくらい。

エロが売りだろうにちっともエロくなく、話も平凡。そもそもこの手のエロって本当に需要があるのか。パンチラとかの方が余程理解できる。

前期より視聴。相変わらずダラーズ創始者がヘタレで、彼にフォーカスが当たると話が一気につまらなくなる。今回の終わり方を見るに、次回は更につまらない予感しかない。

あれで生きてるってないわー、と思ったのも束の間、元々インチキっぽかった主人公に更にチート能力を持たせるという展開に草。前期からの硬派な雰囲気が一気に台無しになった。

話は定番なので特に面白味はない。個人的に OP の動きのある線画が気に入ったが、それが作中には見られなかったのが残念。

調べなくても分かる、「輪るピングドラム」の人だ。輪る~では初話がピークだったが、本作では逆に話が進むにつれて面白くなってくる。ともあれ、ネタとして押さえておくべき作品。

前作から続いての視聴だが、未だに何が良いのか分からない。ヒロインの中の人が「三森すずこ」だったのを再発見したくらい。いっそ OP/ED も彼女に歌って欲しかった。

ファン向けであることを差し引いても、提督未経験の私から見て、絵も綺麗で良く纏まっているように思う。分からないネタも多いが、いろいろと勉強になるので次回も歓迎。

初見の印象は「あざとい」。しかし直ぐに本作の魅力は各ヒロインの個性だと分かる。強いて言うなら、他ヒロインに比べて四人目の個性が弱い感は否定できない。

須世璃にちょっとだけ萌えた以外は、特に取り立てるものがない。キャッチコピーを見ても作中に思い当たる節がないし、アニメ化か原作、どちらかに問題があるのかも。

2015-03-31

Bash: Number of CPU cores

インフラを自動化していると、CPU コア数に応じてパラメーターを変えたい、ということがある。Python では /proc/cpuinfo からそれらを計算するライブラリを自作しているのだが、書き捨てスクリプト、特に Bash で同じことをやりたい。

もちろん Bash でも頑張れば可能ではある。しかし、書き捨てスクリプトでは「空で書ける」ことが重要。欲を言えば、Linux 間で可搬性があるとなお良い。

実は以前にも調べたことがあって、その時は満足のいく方法が見つからなかった。最近になってまた調べると、かなり良さげな方法を見つけることができた。

これを参考にして、

cpuinfo.sh:

#!/bin/bash

ncpu_sockets() {
    cat /proc/cpuinfo \
	| grep -P '^physical id\s*:' \
	| sort -u \
	| wc -l
}

ncpu_cores() {
    cat /proc/cpuinfo \
	| grep -P '^(physical|core) id\s*:' \
	| paste - - \
	| sort -u \
	| wc -l
}

ncpu_processors() {
    cat /proc/cpuinfo \
	| grep -P '^processor\s*:' \
	| wc -l
}

echo sockets = $(ncpu_sockets)
echo cores = $(ncpu_cores)
echo processors = $(ncpu_processors)
# grep '^model name' /proc/cpuinfo | head -1
model name      : Intel(R) Xeon(R) CPU           E5640  @ 2.67GHz

# bash cpuinfo.sh
sockets = 2
cores = 8
processors = 16

やっていることのロジックを理解すれば、これくらいなら空で書くのも難しくない。paste コマンドが初見だったが、手持ちの RedHat 系 OS を見た限り何処にでも入っている基本コマンドのようなので、可搬性も問題ないだろう。

2015-02-18

Python: Unbuffered read and write

今回の環境。少し古いのは、そんな環境でも動かす必要があるから。

# cat /etc/redhat-release
CentOS release 5.5 (Final)

# rpm -q python
python-2.4.3-27.el5

長年システムの仕事をしていると、例えば「出力にタイムスタンプを付けたい」とかいうことが一度くらいはあるはず。普段そんな時は Perl でサクッと作るのだが、今回は訳あって Python を使う必要があった。

この手のスクリプトで考えるべきは、バッファリング制御。Python にもこの手のパターンというのがあって、少しググれば stackoverflow とかに山ほどスレッドが見つかる。

timestamp.py:

#!/usr/bin/python

import fileinput
import os
import signal
import sys
import time

sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)

def main():
    for line in fileinput.input(sys.argv[1:]):
        sys.stdout.write(time.strftime('%F %T ') + line)
    return 0

if __name__ == '__main__':
    sys.exit(main())

上記で、fdopen の「おまじない」部分がそれに当たる。これで標準入出力のバッファリングを無効にしている。その下の signal 云々は、忌まわしき broken pipe を封じる呪文。これも Python 暗黒面の 1 つ。

と作ったスクリプトだが、

# ping -c 5 127.0.0.1 | python timestamp.py -
2015-02-18 18:41:42 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
2015-02-18 18:41:42 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms
2015-02-18 18:41:42 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.014 ms
2015-02-18 18:41:42 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.009 ms
2015-02-18 18:41:42 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.009 ms
2015-02-18 18:41:42 64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.016 ms
2015-02-18 18:41:42 
2015-02-18 18:41:42 --- 127.0.0.1 ping statistics ---
2015-02-18 18:41:42 5 packets transmitted, 5 received, 0% packet loss, time 3999ms
2015-02-03 18:41:42 rtt min/avg/max/mdev = 0.009/0.012/0.016/0.005 ms

全然効いてなーい。めっちゃバッファリングしてる。

前述のおまじない以外にも、Python の起動オプション -u でバッファリングを無効にできるが、それでやっても結果は変わらず。訳が分からないので help & man を良く読んでみる。

# python -h

<...snip...>

-u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
         see man page for details on internal buffering relating to '-u'

# man python

<...snip...>

       -u     Force stdin, stdout and stderr to  be  totally  unbuffered.   On
              systems  where  it matters, also put stdin, stdout and stderr in
              binary mode.  Note that there is internal  buffering  in  xread-
              lines(),  readlines()  and  file-object  iterators ("for line in
              sys.stdin") which is not influenced by  this  option.   To  work
              around  this, you will want to use "sys.stdin.readline()" inside
              a "while 1:" loop.

man の方に衝撃的なことが書いてある。「xreadlines, readlines, ファイルオブジェクトイテレーターは内部バッファリングするから、while + readline を使えよ」って、それってあんまりじゃね? readlines の方はともかく、イテレーターの方は裏切られた気持ちで一杯だ。

と文句を言っても仕方がないので、while + readline で書き直してみる。

def main():
    readline = fileinput.input(sys.argv[1:]).readline
    while True:
        line = readline()
        if not line:
            break
        sys.stdout.write(time.strftime('%F %T ') + line)
    return 0

しかし結果は全く変わらず。もしかして、と思い fileinput の実装を見てみると、

案の定、FileInput.readline で readlines を呼んでおり、ここでバッファリングされるらしい。Python3 でも改善は見られず。なんだよ、fileinput 使えねー。今までファイル入力にはずっと fileinput を使ってきたのに、今後は考え直した方が良さそうだ。

そんなこんなで、最終的には下記のようになった。iter(fh.readline, '') の意味は各自で調べて欲しい。私も今回初めてこの使い方を知った。

timestamp.py:

#!/usr/bin/python

import signal
import sys
import time

signal.signal(signal.SIGPIPE, signal.SIG_DFL)

def main():
    strftime = time.strftime
    write = sys.stdout.write
    for arg in sys.argv[1:]:
        fh = arg == '-' and sys.stdin or open(arg)
        try:
            for line in iter(fh.readline, ''):
                write(strftime('%F %T ') + line)
        finally:
            if fh is not sys.stdin:
                fh.close()
    return 0

if __name__ == '__main__':
    sys.exit(main())
# ping -c 5 127.0.0.1 | python timestamp.py -
2015-02-18 18:46:36 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
2015-02-18 18:46:36 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.019 ms
2015-02-18 18:46:37 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.012 ms
2015-02-18 18:46:38 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.011 ms
2015-02-18 18:46:39 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.009 ms
2015-02-18 18:46:40 64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.009 ms
2015-02-18 18:46:40 
2015-02-18 18:46:40 --- 127.0.0.1 ping statistics ---
2015-02-18 18:46:40 5 packets transmitted, 5 received, 0% packet loss, time 3999ms
2015-02-03 18:46:40 rtt min/avg/max/mdev = 0.009/0.012/0.019/0.003 ms

fdopen のおまじない部分は、なくても動いたので削除した。公式ドキュメントによれば、標準入出力は「行バッファリング」が規定値らしいので、今回の用途ではこれで良さそうだ。

A negative bufsize means to use the system default, which is usually line buffered for tty devices and fully buffered for other files. If omitted, the system default is used.

結局のところ、

  • ファイルオブジェクトイテレーターが入力をバッファリングする
  • fileinput に至っては、Fileinput.readline でさえも入力をバッファリングする

というのが事の元凶だったらしい。特に fileinput、お前はこの手のリアルタイム入力には二度と使わねえ。

まさかこんな単純なスクリプトでここまでハマるとは思わなかった。これでまた 1 つ Python が嫌いになった。使えば使うほど嫌いになっていくのが Python、使うほど手に馴染むのが Perl。:-)


2016-07-18 追記

fileinput の方は、最近になって修正されたっぽい。たぶん 2.7.12 と 3.5.2 から。動作は未確認。

2015-01-31

Animes in the 4th quarter of 2014

アニメは IT エンジニアの必須科目です。 ということで簡単なレビューを。

どう見てもタツミが主人公な件。途中から敵側キャストも拡充されるが、余り盛り上がらずに終息。まあ「どちらかが死ぬ」という設定上、最後が尻すぼみになるのは必然とも言える。

前作は未見。頑張り屋さんのイイ話系かと思ったら、ヒロインが結構ヘタレなのでそうでもない。萌えられるキャラも居なかったが、短尺(15 分)なので見るのは楽だった。

前作からの視聴。相変わらず脚本は聞いている側が恥ずかしくなるレベル。最早ネタのために見てるといっても過言ではない。もちろん次回も見るつもり。

初見で期待してなかったが、やたらと女子キャラのリアクションが可愛い。特にひおたんが秀逸で、監督が苛めたくなる気持ちも分かる。これは是非続きをやってもらいたい。

これこそ私が見たかった正当な Fate な感。しかし主人公が理想を口にするだけのヘタレなことが分かって幻滅。Fate ルートは未視聴だが、見なくても大体予想がついた。多分シリーズでは Fate/Zero が一番ではあるまいか。

ゲーム原作なので全く期待してなかったが、見事に裏切ってくれた。話はもう一押し欲しいが、これだけ丁寧に作り込んでいることに好感が持てる。他のゲーム原作アニメも少しは見習え。

チョロいヒロインにツンデレ彼氏、少女マンガの典型パターン。男が見ても面白味はないが、イケメンなんかに負けないっ→イケメンには勝てなかったよ、に置き換えれば少しは楽しめるか。

何でも脚本が有名人とのことで注意深く視聴していたが、特に何も感じなかった。と言いながら最終話はちょっと涙出してたけど、年寄りは涙腺が弱いので当てにならない。

タイムループ物にしては最後を綺麗に纏めてきたような気もする。が、実は余り良く理解できていない。かといって復習する気もなし。元ネタがエロゲだとは後日知った。

これが噂の進撃(集英社版)ですか。最初は面白く見ていたのだが、火星に降りたくらいから飽きてきた。ゴキがバカっぽいのが原因だと思う。昆虫の勉強には良いのではないかと。

話の内容に言うことはないが、前期に続いて後期もいきなり終わり過ぎ。せめて区切りのある終わり方にしてくれ。劇場版が控えていることは理由にならない。

往年の SEGA 作品が見れて楽しいのだが、ゲーム紹介に留まっていて、当時を生きた老人としては全然足りない。ハードとしてのサターンは好きではなかったが、本サターン(SD キャラ)は可愛くて仕方がない。

主人公強い・ハーレム・ラッキースケベという定番パターンの詰め合わせ。取りあえず、「アーカイブに接続、テーマを実行する」とさえ言っておけば大体合ってる。

清々しい程の中二病に格好良ささえ感じる。各キャラも個性があり絵も綺麗、話も基本コミカルで安心して見れる。この雰囲気を崩さずに、是非第二期をやって欲しい。

魔法少女が不幸を背負うようになったのは、まどマギの罪だと思う。どう終わらせるのか注目していたら、理不尽なハッピーエンドになった。この評価は分かれそうだが、不幸になるよりはマシ。

最初は絵が綺麗なだけと思っていたが、話が進むにつれて各キャラがジワジワ来る。これが原作によるものか、京アニによるものかは不明。フルメタの作者だとは後日知った。

前作からの視聴。パッとしないキャラ揃えからヴィヴィがブレイクするかと思いきや、不発。話も安定の予定調和で終了。萌えられるキャラが居ればまた評価は違ったかも。

前作からの視聴。カムイの言うことがさっぱり分からない上、オカルト現象の種明かしも無し。同じ制作陣が作ったとは思えない。前作が良かったので期待が大きかった分、失望も大きい。

2014-10-31

Animes in the 3rd quarter of 2014

アニメは IT エンジニアの必須科目です。 ということで簡単なレビューを。

主人公が全能過ぎる。ブラコン妹も含めて、各所でネタにされるのも仕方がない。完全に好みが分かれる作品だが、中二病作品の完成形の一つとして、見ておいて損はない。

前作のアップテンポが落ち着いて、ようやく丁度よい感じになった。しかし原作未読で思い入れがないせいか、話が単調に感じる。勉強にはなるので続く限りは見る予定。

無印版を未見でも無問題そうだったので視聴したが、途中からひどい早送り状態。完全にファン向け追加ディスク的な内容だった。寧ろ、これを見たことで原作をやる気が失せた。

また良くあるハーレム作品か、と思っていたら、回を重ねるにつれて各キャラが可愛くなっていった。特にティアがお気に入り。製作者の思う壺な感じだが、素直に続きが見たい。

初話で「GJ 部」のフィギアを見た気がして、てっきり同じ作者だと勘違いした。見終わった後、やっぱりこれが同じ作者のはずがないよね、という結論に。

鉄オタならではの濃い話を見せてくれると思いきや、単なるラッキースケベのハーレム作品だった。そっちは間に合ってるんで、もっと本作品にしかできないことをやってください。

作品については、ほのぼの癒し系くらいしか言うことがない。「ろこどる」が初耳だったので、調べると命名はつんく♂か。「こ」はいったい何処から来たのか。

同性の立場からは主人公(男)にイライラする。ギャグ担当がヒロインくらいしか居ないので、普通に見るには退屈。ただ私的には村尾ちゃんがストライクだったので問題なし。

絶望的な戦力差を覆す主人公にやり過ぎ感を覚えるが、そこに目を瞑れば面白い。それ故に、最終話の早送りには閉口。こういうのを見せられると気持ちが冷めてしまう。

BL 物は今までも幾つか見てきたが、男の娘は初めてかも知れない。話の内容は特にどうということはないが、「シよっ」のセリフは破壊力あり。BL 物でこのセリフは反則だろ。

絵は綺麗で割と好みなのだが、話は主人公強い・モテるの普通のハーレム作品。女子キャラが気に入るかどうかが全て。私的には、青い風使いの人が良かった。

「喰霊-零-」の作者と聞いて。しかし期待に及ばなかった。恐らく「喰霊-零-」の時は、制作者(監督?)の力量による所が大きかったのではないかと推測。

とにかくやたら千代ちゃんが可愛い。今回は「小澤亜李」を覚えた。少女マンガ風なのにガンガン ONLINE と聞いて意外だったが、作者が女性だと知って納得。

「凪のあすから」にインスパイアされた作品か?と思ったら同じ会社とのこと。正直、話の結末には納得が行かないが、何かが心に残る作品ではあった。

話の内容よりも、三森すずこの唄に惚れた。私の中で彼女の株が急上昇。真面目な話、今まで聞いた声優の中で一番かも知れない。でも演技はもう少し頑張って。

基本この手の腐女子向けはスルーなのだが、パステル絵調が好みだったので視聴してみた。結果、やはり見なくても良かったという結論。

前作からの視聴だが、未だに良さが分からない。但し龍子だけは例外。お前はもっと暴れて私を笑わせてくれ。Fate の勉強として、今後も見るつもりではいる。

原作は未読。意外にも、一番つまらないと予想していたアリ編が一番面白かった。但しここがピークだと思うので、どうぞもう作者様はゆっくりお休みください。

今期の一番。「ハートフル」のキャッチコピーは伊達じゃなかった。基本賑やかコメディーで、見ていて全く退屈しない。是非とも続編を希望。ところで「なる」が男だと思っていたのは私だけではないはず。

話はなかなか面白いが、途中で強敵が現れる辺りから雰囲気が怪しくなる。相手が悪役ではなく良きライバルだったなら、もっと盛り上がったのではないかと思う。