Yash 2 その 277: 空文字列と空白が絡む単語展開のバグ
考へれば考へるほどめんどくさい問題が出てきた。また空白やら引用符やらの扱ひに関するバグだ。
space=' '
printf '%s\n' 1 ''$space'' 2
このスクリプトを実行すると、1 と 2 の行の間にいくつ空行が出るか。言ひ換へると、''$space''
はいくつの空文字列に展開されるのか。Yash 2.39 と bash 4.3.42 は空行無し。Dash 0.5.8, ksh-20120801, mksh 52, zsh 5.1.1 は空行が 2 行。
POSIX 2013 に従ふと、四種展開が終はった段階でこの単語は '' ''
となる。続いて単語分割が行はれるが、このとき入力の先頭及び末尾にある IFS 空白類は無視する (IFS white space shall be ignored at the beginning and end of the input.)
といふ決まりに従って空白類を削除すべきなのだらうか。もし削除すると、結果として引用符だけが残り、それ以上の分割は行はれない。その後、引用符除去によって残る一つの空文字列が最終的な展開結果となる。
では、空白類を無視しないとどうなるか。引用符の間にある空白で単語が分割される。結果として、引用符で囲まれた空文字列が二つ残る。よって最終的な展開結果は空文字列二つだ。既述の通り、dash, ksh, mksh, zsh がこの結果を示す。
今の yash はどうか。単語分割の際に空白類を無視した上で、残る引用符もろとも消し去ってしまってゐる。この動きを POSIX の規則に沿って正当化するのは無理があらう。第一の理由として、単語分割で空白類を無視するのはおそらく間違ひだ。引用符除去は単語分割の後に行はれるのだから、単語分割において引用符を存在しないものと見做すのは不自然だ。であれば、空白は入力の先頭・末尾にはないのであって、無視できない。第二に、空文字列を除去できる理由がない。引用符除去の後に空文字列は除去されることになってゐるが、除去していいのは結果が一単語で且つ引用符が無いときだけだ。
これを直すには相当な苦労が必要さうだ。バグの根本的な原因は、yash の内部で引用符除去・空単語除去が早く行はれ過ぎてゐることにある。POSIX の規則では単語分割とパス名展開を行った後に引用符除去が行はれることになってゐる。しかし yash はパラメータ展開の途中で引用符を除去してしまふ。ゆゑに、その後の工程で引用符の有無を認識できない。勿論、各工程を POSIX の規則通りの順序で行へばバグは直る。が、そもそも引用符除去・空単語除去を早く行ってゐるのは、引用符やらバックスラッシュやら複数種類のクォートが入り混じることで文字列のデータ構造が複雑化するのを避けるためであった。どうやら文字列のデータ構造をうまく定義するところからやり直さないといけない様だ。
| 固定リンク
コメント