web-dev-qa-db-ja.com

スクリプトのPATHにディレクトリを追加して、呼び出し元のシェルと残りのセッションに影響を与えるにはどうすればよいですか?

Ubuntuは初めてです。

PATH環境にディレクトリを追加するスクリプトを書きました。スクリプトを実行すると問題なく実行され、dirがPATHに追加されます。しかし、セッションの長さだけ持続するのではなく、スクリプトが終了するまで変化は持続しないようです。スクリプトの実行後にPATHを見ると、ディレクトリはもう存在しません。助言がありますか?

2
JP JP

Sergiy Kolodyazhnyy's answer ここで問題を特定します。スクリプトは、スクリプトを呼び出すシェルの別の子シェルで実行され、変数への割り当てや作業ディレクトリの変更など、シェル自体に影響するコマンドは実行しません。呼び出し元のシェルに影響を与えます。子シェルと(環境に対するexport変数の場合)その子のみに影響します。

あなたは謙虚なシェル変数を使用してこれで遊ぶことができます...

$ foo=bar
$ echo $foo
bar
$ echo -e "foo=baz \n"'echo $foo' > script
$ cat script
foo=baz 
echo $foo
$ bash script
baz
$ echo $foo
bar

Eliah Kaganが この回答 で示しているように、サブシェルを使用する方が簡単です。

あなたが永久にあなたのPATHにディレクトリを追加したくない場合に、この答えを書いていますが、現在のシェルセッションにのみ。

これを行うには、現在のシェルでスクリプトを実行するだけです。これは、.(ドット)に短縮されたsourceコマンドで実行されます。

スクリプトのこの単純化されたバージョンを考えると...

read -rp "What did you want to add to PATH? "
[ -d "$REPLY" ] && 
PATH="$PATH:$(readlink -m $REPLY)" &&
echo "OK, adding $REPLY to PATH" &&
echo "$PATH" ||
echo "seems like $REPLY is not a directory"

通常の方法でスクリプトを実行すると、同じ結果が得られることに注意してください。

$ ./add-to-path
What did you want to add to PATH? /home/zanna/playground
OK, adding /home/zanna/playground to PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground
$ echo $PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

しかし、sourceスクリプトが期待どおりに動作する場合:

$ . add-to-path
What did you want to add to PATH? /home/zanna/playground
OK, adding /home/zanna/playground to PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground
$ echo $PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground

3つの補助を追加します。

  • ~/.profileは現在のシェルから開始されたシェルを含むすべての対話型Bashシェルから供給されるため、~/.bashrcではなく~/.bashrcにPATH割り当てを追加することをお勧めします。 PATH、および~/.bashrcをソースするときに追加するPATH。対照的に、~/.profileは通常、ログイン時(またはログインシェル)からのみソースされます。
  • PATHに割り当てるときにexportは必要ありません。これは既に環境変数であるため、ある意味では既にエクスポートされており、そのままです:PATHへの割り当ては常に子プロセスによって継承されます(ただし、あなたが発見したように、親プロセス!)明示的にexportedされることなく。
  • 全体で変数REPLYおよびPATHを引用しました。シェル拡張をトリガーするスペースまたは他の文字が含まれている可能性があるため、これは良い考えです。ただし、この副作用として、~が展開されないため、スクリプトは次のようなものを返す傾向があります。

    looks like ~/some-existing-dir is not a directory
    

    これは本当です(~をそのまま使用します)が、あまり役に立ちません。たぶん、スクリプトはこれをユーザーに警告するはずです...

1
Zanna