質問: pyenv, rbenv等の使い方として.bashrcなりでeval`"$(XXXenv init -)"`という初期化をする必要があるようですが、2点不明な点があります。 * evalで実行する意味 直接 `XXXenv init -`とするのではなく、evalを使うことにどういった意図があるのでしょうか? * `-`の意味 何を意味しているのか。カレントシェルで実行する`.`みたいなものなのかなとは思っているのですが、情報が見つかりませんでした。 **追記** XXXenv init は標準出力に文字列を返してそれをevalで実行しているのですね。直接実行しないでevalを使わせる理由はなんでしょうか?実行権限をつける必要がないからとかですかね? `-`はただのXXXenvへの引数でしかないことはわかりました。`-`ってどういった意味で使われることが多いのでしょうか?
回答: ### evalについて 今回の場合、`eval`を使いたい理由の1つは、シェルの環境変数や関数を設定したいということにあると思います。変数でも関数でも状況は大体同じなので、以下では変数についてのみ説明します。 `eval`をつけずにinitスクリプトを実行するとわかりますが、`pyenv init`や`rbenv init`ではそれぞれの環境変数を設定するために`export`を使っています。 しかし、シェルにおいてシェルスクリプトはサブシェル等で実行されるため、コマンド内で変数を`export`しても元のシェルにはなんら影響がありません。 たとえば、bashにおいて変数`EXAMPLE`を1に設定したかったとします。このとき、`export`しているシェルスクリプトを直に実行しても意味がありません。 ``` $ cat test1.sh export EXAMPLE=1 $ ./test1.sh $ echo $EXAMPLE $ ``` そこで`eval`を使うと、この処理は以下のように書けます。 ``` $ cat test2.sh echo 'export EXAMPLE=1' $ eval "$(./test2.sh)" $ echo $EXAMPLE 1 $ ``` このような処理をするために、init系のスクリプトで`eval`を使うのではないかと思います。 尚、上の動作は、bashにおいて`.`コマンドないし`source`コマンドを使って`. test1.sh`と書いても良いですが、このコマンドは他のシェルと互換しないことがあります。具体的にはたとえばfishにおいては`.`がdeprecatedで`source`を使うことを推奨していますが(参考1、2)、特定のkshにおいては`source`がありません(参考)。 また、より一般の場合、`eval`を使いたい理由は他にもあります。"eval command in Bash and its typical uses" などをご覧ください。 ### `-`について シェルスクリプトにおいて、ハイフン1文字は「標準入力から読んで下さい」「標準出力に書いてください」といった意味になることが多いです。(そういう意味にしているコマンドが多いというだけであり、普通シェル側が特別に処理する記号になっていないというだけなので、例外はあります。たとえばbashの`cd`ビルトインコマンドでは`cd -`は「1つ前のディレクトリに移る」になります) `pyenv init`においても、ソースコードを見る限り、そのように処理しているようです。`rbenv init`も同様です。 参考 * "What does dash “-” at the end of a command mean?" * "Usage of dash (-) in place of a filename" + "shell script single hyphen" (またはdash) などで検索すると出てきます。