MSYS の Bad File Number 問題

以前ハマったのが何年も前だったもんだから、完全に忘れていたのね。

DOS の数無量大数倍から数無限大倍程度には微かに、わずかに、ほんのちょびっと快適なのでMSYSを使ってはいるものの、本物の Unix の数千から数万倍程度には不愉快なのだね、MSYS。cygwin のやり過ぎデカ過ぎ保守不能性に懲りたもんで、諦めてMSYS使ってる、と言った方がいい。

たとえばこんな Python スクリプト:

hoge.py
 1 #! /bin/env python
 2 # -*- coding: utf-8 -*-
 3 import sys
 4 import os
 5 import argparse
 6 # ...(snip)...
 7 
 8 if __name__ == '__main__':
 9     parser = argparse.ArgumentParser()
10     parser.add_argument('file', nargs='+')
11     for fn in args.file:
12         do_something(fn)

と、こいつのラッパースクリプト:

hoge.sh
1 #! /bin/sh
2 
3 python "`dirname $0`"/hoge.py "$@"

MSYS と、Windows native な CPython (2.7) の組み合わせの場合なら、上記を両方 c:/Python27/Scripts に置けば、「Unix とおんなじように」使える。実行権限を与えなくてもいい、という薄気味悪い特典付き。(.py の方も可視になり、直接実行出来る。)

と、普段ならこれで満足しちゃってたんだけど、今回は違った:

1 me@host: ~$ hoge.sh *
2 /c/Python27/Scripts/hoge.sh: line 3: /c/Python27/python: Bad file number

このエラーは見慣れているはずなのに、1時間は悩んでしまった。どうしても思い出せぬ。

わかってから気付いたのだが、見慣れているは見慣れているが、2種類か3種類の「MSYS でのお約束」がごっちゃになってしまっていた。

MSYS 問題特有とはいえない、Unix 的シェルスクリプト共通の問題には「マジックナンバー問題」があって、「#! 」の部分に何をどう書くか、というのがある。ついつい「Bad ~」からこれだと思い込んでしまってな。

それとな、「file number」に引きずられたもう一つの「違うやつ」には、ファイルディスクリプタの問題がある。これは MSYS というよりは bash の問題。オリジナル bourne-shell は無尽蔵のファイルディスクリプタを作れるが、bash は組み込みの 0~2 しか使えない。実際問題これに関係するわけがないスクリプトなんだから、「なんでそれ?」とさえ思っていた。

あー、思い出した…、と。コマンドライン引数が長過ぎるときの振る舞いなんだよね、これ。

最初期の MSYS では、「*」使うと軒並みダメだったのね。ワイルドカードで大量のファイルが展開されると、コマンドラインが長過ぎる、として死んでた。今の MSYS そのものはこの制約がほとんどなくなったので、すっかり忘れていた。

MSYS 設計がイケてないのは、「MSYS 派閥とそうでないもの」の差別が激しいことである。これは「/」という「文字列が現れると問答無用で c:/msys/1.0/ に置換してまわる」というのもそう。MSYSファミリでない実行ファイルを起動する際にこれをご丁寧にやってくれる。あー、そうか。Windows native の CPython は当然MSYSファミリではないから、MSYSは「MSYSでないので十分にバカ丸出しである」ことを仮定するのだ。つまり「この馬鹿はコマンドライン引数が長いので動くはずがない」ということである。エラーが python を呼び出す前の MSYS シェルレベルで起こってるのが不思議だったのだ。

この制約は直接の回避は出来ない。「MSYSファミリだけが賢い」というMSYSの思い込みに従うのみである:

1 me@host: ~$ for i in * ; do hoge.sh $i ; done
2 ...

うん。もう書いたので、二度と忘れないだろう、たぶん…。












つーか、MSYSに対する思い入れはワタシにはないもんで、全然古いまんま使ってるんだよね、アタシ。最初に書いた通り「DOS でなければそれでいい」への期待にだけ応えてくれればいい、なんて、これは思いいれゼロてこと。なので、最新のMSYSでは状況違ってるかもしんないです。けどんなこと知らん、あたしゃ。












なお、ワタシ自身はほとんど間違えないので今でも問題かどうか既にわからないのだが、シェルスクリプトの改行コードも、確か Unix コード(LF)でないとダメじゃなかったかな。(癖で必ず LF にしちゃうので、ワタシ。だからわからん。)

ところで Bad file number と UAC が関係がある、という情報を見つけたんだけど、本当だろうか? ワタシと同じように、何かと混同したりしてない?