ttt

getttyent

ずっと/bin/shの「$@」の使い方を間違えていた

2009-02-26 23:59:00 | デジタル・インターネット

なんかみっともない話ですが、使い方を間違えてたんです・・・。

$@は、コマンドラインで指定した引数が入ってくるんですが、引数にスペースを含んだ文字列を指定した場合の振る舞いが特徴的です。
こんなシェルスクリプトで動作確認ができます。

#! /bin/sh
i=0
for a in "$@"
do
    echo $i : $a
    i=`expr $i + 1`
done

ためしに実行してみると

% sh ./arg.sh abc "def ghi"
0 : abc
1 : def ghi

という動きをします。

これを、私はずっと間違えていて、こう書いてたんです。

(一部のみ抜粋)
for a in $@
do
    echo $i : $a
    i=`expr $i + 1`
done

ただ、「"$@"」と「$@」の違いだけなんですが、動きは大違い。

% sh ./arg.sh abc "def ghi"
0 : abc
1 : def
2 : ghi

スペースが入ってると、そこで分離されてしまうんですね。
というわけで「"$@"」と書かなければならない!ということ。

$@によく似た変数で、$*があります。

"$*"」で使うと・・・

(一部のみ抜粋)
for a in "$*"
do
    echo $i : $a
    i=`expr $i + 1`
done

実行してみます。

% sh ./arg.sh abc "def ghi"
0 : abc def ghi

$*」で使うと・・・

(一部のみ抜粋)
for a in $*
do
    echo $i : $a
    i=`expr $i + 1`
done

実行してみると

% sh ./arg.sh abc "def ghi"
0 : abc
1 : def
2 : ghi

なんか微妙・・・これはまる暗記して覚えるしかないのかも。


こういう書き方

i=`expr $i + 1`

を最初に覚えたので、ずっとこの書き方を使ってるんですが、今どきの/bin/shでは

i=$((i+1))

という書き方もできるそうです。

i=$(($i+1))

と書いても同じ結果になるんですが、ふ~ん。

exprを使わなくてすむ分、性能向上しそうなので、じゃあ、これからこっちにしよう!と思ったら、Solarisの/bin/shではこの書き方、使えませんでした。ぎゃふん。


(FreeBSD) フロッピーディスクに書き込めなくね?

2009-02-25 23:59:00 | デジタル・インターネット

21世紀。もういらねーだろ、と思っていても、数年に1度くらいの頻度で、フロッピーディスクを使わざるを得なくなるはめになることがあるのです。
というわけで、FreeBSDでフロッピーディスクに書き込もうとすると・・・

とりあえずフォーマット

# fdformat fd0
Format 1440K floppy `/dev/fd0'? (y/n): y
Processing VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV done.

書き込む

# cat HOGE.IMG > /dev/fd0
cat: stdout: Input/output error

だめじゃん。

ddならどうだ?

# dd if=HOGE.IMG of=/dev/fd0 bs=512
dd: /dev/fd0: Input/output error
37+0 records in
36+0 records out
18432 bytes transferred in 4.378225 secs (4210 bytes/sec)

だめじゃん。

ってな感じで、書き込めないことがよくあります。

めったに使わないせいで、ドライブかメディアがだめになっているのかもしれません。しかし、これまでの経験上、どうもFreeBSD上でやると、かなりの高確率でエラーがでるような気がしてなりません。


(2009/2/26) 37の謎

別のフロッピーディスクを使ってみたところ、ddで、同じところでエラー発生。
1.44MBの2HDのフロッピーディスクは、18セクタ 2ヘッド 80シリンダなので、37 = 18*2 + 1 ということで、2つめのシリンダに移動したあとエラーが起きた、ってことで、なんとなく意味ありげ。

とはいえ、これだけで、ソフトウェアとハードウェアどちらに問題があるかは決められないですけど。


(FreeBSD) portsのmono-2.0.1_6のmake中に暴走しちゃう

2009-02-24 23:47:51 | デジタル・インターネット

最近、portsのmonoがバージョン2.0になったときからだと思うのですが、半年くらい前の古いFreeBSD 6.3-STABLEなマシンで、monoをportupgradeしようとすると、途中で処理が先にすすまなくなります。
単純に、portsのmonoをmakeするだけでも同様。どうもmonoのプロセスが暴走してるらしく、CPU使用率も100%近くになります。

それとは別の、FreeBSD 7.1なマシンだと、正常にmakeできてます。

gdbで見てやろうとattachすると、スレッドの処理のどこかにいるみたい。

「ktrace -p プロセスid」してみたら、たしか、segmentation faultみたいなエラーがえんえんと出ていました。

なんとなくの思いつきで、/etc/libmap.confに

[mono]
libpthread.so.2                 libthr.so.2
libpthread.so                   libthr.so

を書き換えたら、正常に(?)makeできるようになりました。

ま、いいか。

monoは何かの依存関係でインストールされてしまっただけで、とくに積極的に利用しているつもりはないし・・・


(FreeBSD) locale設定とphpのfgetcsvの挙動の関係がよくわかんない

2009-02-23 22:43:14 | デジタル・インターネット

なんか勘違いしてるのかなぁ~?

fgetcsvを使って、こんなphpスクリプトを書いてみました。

% cat csvtest.php
<?php
$fp = fopen("csvtest.csv","r");
while( FALSE != ($data=fgetcsv($fp)) ) {
  echo "data=";
  print_r($data);
}
?>

「csvtest.php」をダウンロード

読み込むCSVファイルcsvtest.csvはこんな内容。

% cat csvtest.csv
1,2,3,"あいうえお",4,5,6
2,3,"あいうえお",4,5,6,1
3,"あいうえお",4,5,6,1,2

「csvtest.csv」をダウンロード

文字コードは、日本語EUCにしてあります。

% hd csvtest.csv
00000000  31 2c 32 2c 33 2c 22 a4  a2 a4 a4 a4 a6 a4 a8 a4  |1,2,3,"あいうえ・
00000010  aa 22 2c 34 2c 35 2c 36  0a 32 2c 33 2c 22 a4 a2  |・,4,5,6.2,3,"あ|
00000020  a4 a4 a4 a6 a4 a8 a4 aa  22 2c 34 2c 35 2c 36 2c  |いうえお",4,5,6,|
00000030  31 0a 33 2c 22 a4 a2 a4  a4 a4 a6 a4 a8 a4 aa 22  |1.3,"あいうえお"|
00000040  2c 34 2c 35 2c 36 2c 31  2c 32 0a                 |,4,5,6,1,2.|
0000004b

phpの関数fgetcsvは、CSVファイルを読み出して、フィールドごとに分解してくれるのですが、マニュアルによれば

http://www.php.net/manual/ja/function.fgetcsv.php

注意: この関数はロケール設定を考慮します。

ということになっています。

localeをCにして実行してみると

% env LC_CTYPE=C php csvtest.php
data=Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => あいうえお
    [4] => 4
    [5] => 5
    [6] => 6
)
data=Array
(
    [0] => 2
    [1] => 3
    [2] => あいうえお
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 1
)
data=Array
(
    [0] => 3
    [1] => あいうえお
    [2] => 4
    [3] => 5
    [4] => 6
    [5] => 1
    [6] => 2
)

これは、まあそういうこともあるかな、という結果。

ところが、localeを、日本語EUCのja_JP.eucJPにすると

% env LC_CTYPE=ja_JP.eucJP php csvtest.php
data=Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => あいうえお",4,5,6
2,3,あいうえお"
    [4] => 4
    [5] => 5
    [6] => 6
    [7] => 1
)
data=Array
(
    [0] => 3
    [1] => あいうえお",4,5,6,1,2

)

ダブルクォート「"」を見失って、「迷走」してます。どうして?

最初、ja_JP.EUC-JPにしたら

% env LC_CTYPE=ja_JP.EUC-JP php csvtest.php
data=Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => あいうえお
    [4] => 4
    [5] => 5
    [6] => 6
)
~以下略~

となって、意図どおり動いているように見えたんで、locale名が間違ってるのか、と思ったんですが、どうもこちらは、ja_JP.EUC-JPなんていうlocaleは存在しないので、C相当の動作になっている、ってことらしいです。

さて、エンコードをUTF-8にしてみると

% mv csvtest.csv csvtest.csv.org
% iconv -f EUC-JP -t UTF-8 csvtest.csv.org > csvtest.csv

% env LC_CTYPE=ja_JP.UTF-8 php csvtest.php | iconv -f UTF-8 -t EUC-JP

data=Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => あいうえお
    [4] => 4
    [5] => 5
    [6] => 6
)
data=Array
(
    [0] => 2
    [1] => 3
    [2] => あいうえお
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 1
)
data=Array
(
    [0] => 3
    [1] => あいうえお
    [2] => 4
    [3] => 5
    [4] => 6
    [5] => 1
    [6] => 2
)

ということで、UTF-8なら大丈夫っぽい。

ちなみに

% env LANG=ja_JP.UTF-8 date | iconv -f UTF-8 -t EUC-JP
2009年 2月23日 月曜日 22時30分10秒 JST

なので、ja_JP.UTF-8というlocale名は正しいと思う。

デフォルト設定では、こんな感じになってるんですが、何か関係あるのでしょうかね。よくわかってないままphpを使っていたりするのが悪いのかも。

% php -i | grep -i encoding
iconv.input_encoding => ISO-8859-1 => ISO-8859-1
iconv.internal_encoding => ISO-8859-1 => ISO-8859-1
iconv.output_encoding => ISO-8859-1 => ISO-8859-1
mbstring.encoding_translation => Off => Off
mbstring.internal_encoding => no value => no value
mbstring.script_encoding => no value => no value
SQLite Encoding => UTF-8

わかんないことがあればソースコードを見ろ!ってことで、cd /usr/ports/lang/php5/; make patchして、grepでそれらしい場所を推測して、眺めてみました。オープンソースって便利だね。FreeBSDって便利だね。

mblenとかいう、マルチバイトを考慮して文字列長を調べるのかな?って感じの関数が使われていましたが、よくわかんなかったです。


2月22日は猫の日らしい

2009-02-22 23:32:44 | 日記・エッセイ・コラム

私は犬派。これまでの人生で、猫に触ったことさえほとんどなく、どうでもいいんですが。

犬の日は1月11日か?と思いきや、11月1日らしい。それとは別に「戌の日」ってのもあるそうだ。たしか腹帯を巻く日?

こいつ・・・

200902221

そんなこと↓言ってるけど

200902222

ぜったい、猫じゃねぇっ! って思う。

ドラえもんのヒントになったのは、「ポロンちゃん」という、赤ちゃんの形をした“おきあがりこぼし”人形だった、という話が、「ドラえもん誕生」という作品に描かれていました。ポロンちゃんと猫を足した、ってことになってましたが…。

あと、ドラえもんの色が青いのは、「小学一年生」などの雑誌掲載時はカラー印刷になるので、ちっちゃな子供がよろこぶように、カラフルな色使いをしたいと思ったとき、青ってあんまり使うところがないな、じゃあ主人公を青くしてしまえ、とかいう大胆な理由だった、という話を読んだ記憶があるんですが、こっちはうろおぼえ。当時のカラー印刷技術の制約だったという話もあったような。

もしかして、今年の12月で、ドラえもん誕生40周年ですか?1969年12月発売の雑誌で登場したはずなので。


確定申告の季節なんですね

2009-02-21 20:21:08 | デジタル・インターネット

確定申告が始まってるんですね。学生のころは、自分で何度かやってましたが(学生だと控除が少ねぇ、サラリーマンうらやましい、とか思ってた)、会社員となってしまった今は、年末調整で済んでしまっていて、まったくの無縁。病院にも行かないし、株取引もやんないし、自然災害にもあってないし・・・

昔はExcelで必死に計算しながら用紙に書き込んでたんですが、今は、e-Taxとかいうインターネットで確定申告できる仕組みがあるんですね。MacOSではできないよ~、とか、なんだかな~って感じもありますが、手間を省くためにはやむをえない、ってところでしょうか。

いったい何につかうんだ?っていう雰囲気もしますが(笑)、パソコンでICカードを読み書きする機器を持ってます。

200902211

SCR3310-NTTCom

e-Taxとも無縁だし、住基カードって何?って感じの私ですが…

こんなのマイナーな周辺機器だろうと思ってたんですが、店頭では、何種類も、たくさんうってました。1月中ごろの話。

e-Taxのウェブサイトを見て、たまたま気がついたんですが、

200902212

「MMX Pentium 226MHz」なんていう製品は、なさそうな感じ。

CPUのクロック周波数は、だいたい33の倍数なので(33.3くらい。PCIバスのクロック周波数が元になっているのかな)、33.3×7≒233、33.3*8≒266ということで、233MHzか、266MHzの間違いじゃないかと思います。


上に書いてある仕様を満たすパソコンってのは、だいぶ古いパソコンに相当するので、ネットブックでも十分…と思ったら、画面解像度が満たせてないですね。


(Solaris10,pkgsrc) lddしたら、libz.so.1 (SUNW_1.1) =>

2009-02-20 21:52:10 | デジタル・インターネット

いきなり無駄話から。

10数年前くらい前は、ソフトウェアをインストールするときは、自分でMakefileを書き換えたり、config.hとかいうファイルを書き換えたりして、makeして、エラーがでたらソースを直したり、インストールするには、手でファイルをコピーしたり・・・そんな感じ。

だんだんとautoconfが使われるようになってくると、「configure; make ; make install」の3つのコマンドだけで、インストールできるようになりました。これはすごい便利だ!と感動ものでした。

ただ、make installはあっても、make uninstallのようなものはなくって、アンインストールしたい、とか、バージョンアップしたい、とかいうときは、それはそれで面倒なことになります。

ちょうどそのころPC UnixとかLinuxが台頭してきましたが、「ソースからコンパイルするなんてめんどくさい。バイナリファイルをコピーするだけですむ、バイナリパッケージでいいんじゃね」的なスタイルも増えていきました。まだまだCPUパワーが低かったので、「make world」を実行すると、本当に1週間かけて「天地創造」しちゃう・・・という理由もあったかと思います。

FreeBSDでもバイナリパッケージはありますが、そのバイナリパッケージを作る仕組みとして「ports」があります。これは、ソフトウェアをインストールするための手順を記述したMakefileと、インストールすべきファイルの一覧リスト、必要に応じていくつかのpatchファイルなどから構成されています。makeと実行するだけで、自動的にソースコードをダウンロードして、自動的にソースコードからコンパイルしてくれます。しかも、コンパイルするときに、いろんなカスタマイズができるので、おまかせのバイナリ・パッケージでは不可能な、自由度の高さ、これが私のお気に入りなのです。

パッケージ管理の仕組みに頼らずに、自分でコンパイルしてインストールする、いわゆる「野良ビルド」がよくないのは、アンインストールやバージョンアップが簡単にはできない、っていう理由もありますし、インストールした人じゃないと、どういう設定でインストールしたのかがわからないので(メモが残してあったとしても、本当にそのメモが正しいとは限らなかったり)、管理者が変わると、もうわけわかんねぇ無秩序な状況に陥ってしまうことだと思います。
たった一人で使っているマシンなら、その人が責任をとればいいだけですけどね。
でも、FreeBSDのportsは異様に充実してて、私の場合、インストールしようと思うソフトは、ほぼすべてportsに入ってます。だから野良ビルドは、ほとんど無いです(fvwmとxemacsだけかな)。
「googleで見つからないウェブページは、存在しないのと同じ」と言われることがありましたが、それと同様に、「portsに入ってないソフトウェアは、存在しないのと同じ」と言ってもいいかもしれない、と思ってます。

FreeBSDのportsとよく似た仕組みが、NetBSDではpkgsrc(ぱっけーじ・そーす、って言うのかな?)という名前で用意されています。てゆーか移植版?
pkgsrcのすごいところは、NetBSD専用というわけではなくて、Solaris、Linux、FreeBSDなど、さまざまなプラットフォームに対応しているところ。残念ながら、私の周りには、NetBSDは無いのですが・・・。

Solaris、Linux、FreeBSDさまざまなマシンが混在する環境で、まったく同じソフトウェアをインストールすることができるので、プラットフォームの違いを極力感じさせない、使い勝手のよい計算機環境を提供できます。
あと、pkgsrcって、管理者権限がなくても、一般ユーザーで利用することができます。デフォルトでは、/varとか/usrとか、一般ユーザーでは書けないディレクトリにファイルを置いてしまいますが、最初のインストール時に、どのディレクトリにファイルを置くか指定できるようになってます。

というわけで、pkgsrcもお気に入りなんですが、マルチ・プラットフォーム対応!と大風呂敷を広げているせいか、やっぱり細かいところで漏れはあるみたいで、たとえばSolarisで使っていると、たびたびよくわかんないエラーがでることもあったり。

あ、そうそう、FreeBSDで、portsとpkgsrcの両方を使うことも、不可能ではないのですが、たまにトラブルが起きます。同じディレクトリ名を使っていたり、同じコマンド名があったり、似たような名前の共有ライブラリがありますので。mk.confや環境変数を工夫することで、だいたいなんとかなるんですが。
これまで困ったのは、portsとpkgsrcの両方でphpをインストールしてあるとき、portsでphpをビルドしようとすると、configureスクリプトが、pkgsrcで/usr/pkg以下にインストールしてあるファイルを先に見つけてしまう、ってことがありました。「mv /usr/pkg /usr/pkg-」とかやって、毎回、お茶を濁しています。

以前、SPARCなSolaris10で、pkgsrcを使っていろいろソフトをインストールしてあったんですが、インストールしたまんま放置してたので、先日、ひさびさにアップデートしておこう、という気分になりました。

そしたら、あちこちで、共有ライブラリが見つからなくてビルドに失敗。

lddで見ると(一部のみ抜粋)、

libgcc_s.so.1 =>         /usr/pkg/gcc3/lib/libgcc_s.so.1
libgcc_s.so.1 (GCC_3.4) =>       (version not found)
libz.so.1 =>     /usr/pkg/lib/libz.so.1
libz.so.1 (SUNW_1.1) =>  (version not found)

という感じの、おかしな状況が発生してました。

まずはzlibの問題について。

これ、どうやら、もともとOSの一部として存在していた/usr/lib/libz.soと、pkgsrcでインストールした/usr/pkg/lib/libz.soの、両方が混在して使われてしまっているらしいです。

たぶん、pkgsrcでインストールするソフトは、常に/usr/pkg/lib/libz.soを使ってくれればいいはずなので、それってどうやるんだろう?と思い、デバッグオプションを指定してbmakeしたり、pkgsrc/mk/以下のファイルをgrepして眺めてみたりしていて、ようやく発見しました。

/etc/mk.confに

PREFER.zlib = pkgsrc

と書いておけばよいみたいです。

この設定をしてから、zlibを利用しているソフトを再ビルドして、とりあえず解決。

ところで、pkgsrcの仕組みって、とっても変わっています。ビルド中には、作業ディレクトリの下に、
work/graphics/freetype2/work/.buildlink/lib/
といったディレクトリが作られて、このディレクトリ内に、各種共有ライブラリへのシンボリックリンクが張られて、このディレクトリを指定してリンクしてます。
PREFER.zlib = pkgsrc を書くと、.buildlink以下に、libz.so*へのシンボリックリンクが作られるようになりました。
コンパイル中に実行する各種コマンドも、/usr/pkg/bin/や/usr/bin/以下のコマンドが実行されるのではなくて、ラッパースクリプトがwork以下に作られて、ラッパースクリプトを実行するようになっています。
こうやって、プラットフォームの違いを吸収してるんですね。感心しました。

つぎにlibgcc_s.so.1の問題。

こっちは難しかった。あれこれ再ビルドしても、どうしても

libgcc_s.so.1 (GCC_3.4) =>       (version not found)

が出るんです。gcc34の再ビルドまでして、試行錯誤していくうちに、lddの表示が変化しました。

libgcc_s.so.1 =>         /usr/pkg/lib/libgcc_s.so.1
libgcc_s.so.1 =>         /usr/pkg/gcc34/lib/libgcc_s.so.1

おぉっ! なんか、2つ混じってる。

/usr/pkg/lib/libgcc_s.so.1 の方は、タイムスタンプがけっこう古くて、昔インストールしたgccの残骸ファイルみたいでした。というわけで、こっちを削除。

あとは、いくつか再ビルドして、やっとこさ問題解決できました。

自分でももう忘れていたんですが、昔書き残しておいた

(Solaris10) gcc -std=c99のとき、Undefined symbol __builtin_isnan となってエラー

の中に、

pkgsrcで、lang/gcc34が、すんなりとはビルドできなかった

という記述があって、そのときもzlibでトラブルがおきてました。
「-lz」で指定すると、64bitバイナリのビルド中に、32bitバイナリなlibzをひっぱってきてしまう、というのがトラブルの原因です。

当時は気がつかなかったことに、今回、気がつきました。

ビルド中の作業ディレクトリの中を眺めていたら、その中に、gcc34が自前で用意しているらしいzlibがありました。ただ、名前が微妙に変更されています。こんな感じ。

lang/gcc34/work/obj/sparc-sun-solaris2.10/sparcv9/zlib/libzgcj_convenience.la

というわけで、「-lz」の代わりに、libzgcj_convenience.laを使ってやればいいんじゃね?ということ。

エラーが出るのは、libjavaを作ってる途中なんですが、

lang/gcc34/work/obj/sparc-sun-solaris2.10/sparcv9/libjava/Makefile

の中で

SYS_ZLIBS = -lz

となっているところを

SYS_ZLIBS = ../zlib/libzgcj_convenience.la

に変更すれば、うまいことビルドできました。

いや、途中、attempted multiple inclusion of fileというwarningが、何度も出てましたが、見なかったことにしておきます。

それと、Makefileを書き換えても、32bit版のほうが再ビルドされなかったので、手でファイルを削除して、強制的に作り直させました。

そんなに苦労するんだったら、素直にバイナリパッケージを使えばいいのに、って思う人もいるんだろうなぁ・・・