01-Apr-2009: Beta 1 of OpenSSL 1.0.0 is now available, please test it nowエイプリルフールにきまってる。0.9.x のままあと10年戦ってください。
_ Linux 上で #!/usr/bin/sed -f なスクリプトを書いた。実行。
は? なんぞ?-bash: ./hoge.sed: /usr/bin/sed: bad interpreter: No such file or directory_ 今までぜんぜん気づいてなかったが、Linux の世界では sed は /usr/bin じゃなくて /bin らしい。キモい。キモすぎる。
_ こういうパスの違いを吸収するには env を使うんだ!とばかりに
とすると、動きません。 理由。shebang 行の環境依存性を排するなんて幻想でしかないんだ。#!/usr/bin/env sed -f
_ きょう新人くんがハマってた。って、もう今月からは2年目くんか。
_ 実行結果として以下のような複数行の応答を返すコマンドがある。
で、このコマンドをこんなふうに sh スクリプトから呼び出す。hoge fuga piyo moga abcdefg 1234567890 AAAAAA zzzzresult=`なんかコマンド` echo $result_ 彼はコマンドの実行結果とまったく同じものが出力されると期待してたんだけど、現実は無惨。
こんなわけわからんものが出てきて、なんでーと泣きついてきた。zzzzAA7890iyo moga_ 彼の教育を考えるのであれば適当にヒントだけ与えて自分で理由と解決策にたどりつけるようにしてやれればよかったんだろうけど、夕方近くにもなってまだ昼飯も食う時間も取れてないようなときに「やっぱダメです」「そりゃここがおかしい」なんてやりとりを何度もやってられんので、なぜこうなったのか、どこを修正すればいいのかをさっさと説明して終わらせてしまった。
_ ちうことで、ここではヒントだけ書いておくので、何がおかしくてこんなことが起きちゃったのかは自分で考えてね。ちゃんとした答はそのうち書く。「echo は引数をそのまま出力するコマンドじゃなくて引数リストを空白で連結したものを出力するコマンドだよ」
_ 罠はふたつある。片方は罠というより単に無知なだけといった方がいいかもだけど。
- echo の実行の前にシェルにより $result の引数展開がおこなわれるので、echo の引数はひとつのように見えて実はひとつではない。
- 例のコマンドの出力は、実は改行が LF ではなく CR+LF だった。
_ 前者。変数の中身に改行コードはちゃんと残っているが、シェルにとっては改行もスペースと同じように引数の区切り文字のひとつでしかない。で、echo は引数をそのまま出力するコマンドではなく、引数リストを空白で連結して出力するコマンドであるから、結果として変数に含まれる改行(LF)が空白に変換されることになる。
_ 後者。CR はカーソルを行頭に戻す。LF は1行送る。DOS/Windows では CR+LF で改行を表現するけど、UNIX では LF だけで改行を実現する。CR が特別な意味をもたない UNIX で動く sh にとって、LF は区切り文字だけど CR は区切り文字ではないが、端末にとっては行頭に戻すという CR の制御コードは有効。
_ つーわけで、変数が展開された後、echo でほんとのほんとに出力される文字列はこうなる。
このとおりちゃんと出力されるが、LF のない CR のせいで何度も行頭に戻って画面上の同じ場所に文字を上書き表示するため、最終的に画面に残るのはhoge fuga piyo moga<CR> abcdefg<CR> 1234567890<CR> AAAAAA<CR> zzzz<CR>という謎文字列になる。端末に直接表示させず、CR の機能を無視するツール(less とか od とか)に出力を食わせてみれば、ほんとの出力を確認できる。zzzzAA7890iyo moga_ で、この困った現象をやめさせるにはどうすればいいか。よーするに $result という1個の変数がシェルに展開されて複数の引数として echo に渡されてしまってるのが元凶なわけなので、これを1個の引数のまま echo に渡せばよい。つまり、
とする。だからあれほどシェルの変数はダブルクォートで括れといったのに。括らず生のまま使ってわざとシェルに分解させて使うこともあるけど、どっちかというと高等テクニックなので、シェルの引数展開のしくみをちゃんと理解するまではとりあえずダブルクォートで括っとけ。echo "$result"_ なお、"$result" としても CR がまだ残ったままなので、場合によっては CR を除去しておいた方がいいかもしれない。つまり、
とする。echo するときに除去してもいいけど、たいていの場合は先に CR を除去しておいた値を変数につっこんでおいた方がしあわせ。result=`なんかコマンド | tr -d \\r`_ で、その2年目くんに「ダブルクォートの方はともかく、CR のことなんて man に書いてないですよねぇ。そういうのどこで知るんですか」と聞かれた。うーん。どこと言われても。あちこちで、としか言えんぞ。