torus / 42-minishell

貝殻のように美しい。
9 stars 1 forks source link

リダイレクションの環境変数展開を実装する #62

Closed JUNNETWORKS closed 3 years ago

JUNNETWORKS commented 3 years ago

リダイレクションに環境変数が渡されていた場合, コマンドの引数の場合と少し違う挙動をするので別Issueを立てた.

JUNNETWORKS commented 3 years ago

27 からコピー:

image

Originally posted by @torus in https://github.com/torus/42-minishell/issues/42#issuecomment-823048679

JUNNETWORKS commented 3 years ago

あ、#27 がこれのつもりでした。展開は t_command_invocation を作る段階でやっておく必要があります。変数の展開後にスペースが含まれている処理が必要なんですが、これはコマンドの引数の場合とリダイレクトのファイル名の場合で必要な処理が変わります。

たとえば、$A="ABC DEF" のとき、単に $A というコマンドラインの場合は、abc というコマンドと def という引数に展開されますが、echo > $A のときにはエラーを発生させる必要があります。

Originally posted by @torus in https://github.com/torus/42-minishell/issues/42#issuecomment-823042722

JUNNETWORKS commented 3 years ago

image

パースの時点でエラーとなっているっぽくて, そもそもコマンド実行がされない(リダイレクトで指定されたファイルが作られてない)

JUNNETWORKS commented 3 years ago

image

環境変数の値が空文字列の場合もエラー

JUNNETWORKS commented 3 years ago

image

環境変数が存在しない場合もエラー

JUNNETWORKS commented 3 years ago

環境変数が空文字列 image


環境変数が存在しない image


環境変数にスペースが含まれている image


環境変数にリダイレクト記号がある image


リダイレクトの途中でスペース区切りの環境変数が入っている image


リダイレクトが複数あり, その中に不正なリダイレクト先が含まれる場合, そのリダイレクト先まではファイルが作られるが, 不正なリダイレクト先移行のリダイレクト先はファイルが作成されない. (画像では $ABC="abc def")

image

JUNNETWORKS commented 3 years ago

ASTからcmdinvoに変換するタイミングか, リダイレクトで指定された各ファイルのopen失敗したタイミングでエラーを返すかがわからん...

JUNNETWORKS commented 3 years ago

ダブルクオーテーションで囲むと正しく動く. image

本当にどこでエラーを判定すればよいのだ...

torus commented 3 years ago

最初にぼくがイメージしていた動作は次のようなものです。これで多分ひととおりカバーできていると思うんですが、ダメなケースはありますかね?

共通の動作

例:$A="a b" のとき x$A"y z" は次のトークン列になります:

次に EXPANDABLE の中に $ が含まれているので、展開します。すると次のようになります:

さらに、EXPANDABLE について空白で区切ります。すると 1 個目の EXPANDABLE が 2 個に別れて、最後の要素は次の y z とくっつきます:

y z は QUOTED なので、split はしないことに注意してください。

これにより、最終的に 2 個の引数列に展開されます。

リダイレクト先の処理

torus commented 3 years ago

ちなみに、変数の展開はパースのあとで行われるので、> などの文字も特別扱いはしません。

$ export A='>'
$ echo $A
>
$ echo hello > $A
$ ls
'>'
$ cat '>'
hello
$ 
JUNNETWORKS commented 3 years ago

最初にぼくがイメージしていた動作は次のようなものです。これで多分ひととおりカバーできていると思うんですが、ダメなケースはありますかね?

共通の動作

  • 変数展開は TOKTYPE_EXPANDABLETOKTYPE_EXPANDABLE_QUOTED に対してのみ行います。

    • 変数がセットされていないときは単なる空文字列に展開します。
  • その次に展開済みの TOKTYPE_EXPANDABLE に対して ft_split をして、空白が含まれていれば複数の引数に分割します。TOKTYPE_EXPANDABLE_QUOTED に対しては split してはいけないことに注意してください。

例:$A="a b" のとき x$A"y z" は次のトークン列になります:

  • EXPANDABLE (x$A)
  • EXPANDABLE_QUOTED (y z)

次に EXPANDABLE の中に $ が含まれているので、展開します。すると次のようになります:

  • EXPANDABLE (xa b)
  • EXPANDABLE_QUOTED (y z)

さらに、EXPANDABLE について空白で区切ります。すると 1 個目の EXPANDABLE が 2 個に別れて、最後の要素は次の y z とくっつきます:

  • xa
  • by z

y z は QUOTED なので、split はしないことに注意してください。

これにより、最終的に 2 個の引数列に展開されます。

リダイレクト先の処理

  • 展開後の引数の数がちょうど 1 個でない場合(ゼロまたは複数のとき): 「曖昧なリダイレクト」のエラー
  • 展開結果がちょうど 1 個のときはファイルをオープンして、失敗したらエラー

以下のケースの場合, 上記のロジックだと上手く行かないと思います.

$ABC=" a b " で, 入力が $ABC"c d". この時出力は

のようになるはずですが, ひさいさんのおっしゃってたロジックだと

のようになると思います.

torus commented 3 years ago

おお確かに。ft_split する時に、文字列の先頭と末尾が空白でないか確かめる必要がありますね。