以前同期と bash でパイプライン cd を使えると便利だよねーという話から次のような override cd の関数を考えた。
function cd() { if [ -n "$1" ]; then arg=`cat` builtin cd "$arg" fi }
こうすると echo $HOME | cd
とかで移動できるが、これを bashrc に登録したことで共有された bash スクリプト内で cd を行う時に事故が多発したという話を聞いた。
それは大変だと思いながら放置をしていたが、ふと思い出して試してみたことを記述。 環境は macOS High SIerra。
試しに bashrc に次のような記述を行う。
function cd() { echo "Hello, RC!!"; builtin cd "$@" && ls -l; }
こうすることで bash を起動して cd を行うたびに次のようにディレクトリ移動後に ls が動作をする。
bash-3.2$ cd ~ Hello, RC!! total 0 drwx------@ 3 codehex staff 96 3 23 21:39 Applications drwx------+ 23 codehex staff 736 4 28 23:20 Desktop drwx------+ 4 codehex staff 128 4 13 11:30 Documents drwx------+ 17 codehex staff 544 4 26 12:53 Downloads drwx------@ 60 codehex staff 1920 4 19 16:11 Library drwx------+ 3 codehex staff 96 3 23 17:37 Movies drwx------+ 4 codehex staff 128 4 19 10:37 Music drwx------+ 3 codehex staff 96 3 23 17:37 Pictures drwxr-xr-x+ 4 codehex staff 128 3 23 17:37 Public lrwxr-xr-x 1 codehex staff 83 4 2 11:05 com.googlecode.iterm2.plist -> /Users/codehex/.ghq/github.com/Code-Hex/dotfiles/iterm2/com.googlecode.iterm2.plist drwxr-xr-x 5 codehex staff 160 4 2 11:54 go bash-3.2$ pwd /Users/codehex
#!/bin/bash echo "Run bash script!!" cd ~ cd ~/Desktop pwd
このスクリプトを eg.sh
として保存し chmod 0755 eg.sh
とかしてあげることで ./eg.sh
というように実行することができる。
これでもし自分が使っている bashrc が使用されれば eg.sh 内で記述されている cd を実行する時に ls も実行されるはずである。 しかし実行してみると次のような結果が得られた。
bash-3.2$ ./eg.sh Run bash script!! /Users/codehex/Desktop
shebang で指定された bash はちゃんと bashrc をロードせずにデフォルトの状態でスクリプトを実行していることが分かる。 しかし、次のような一行を bash スクリプト内の shebang の次の行くらいに記述していると話は別である。
source ~/.bashrc
この状態で ./eg.sh
を実行してみると次のような結果が得られた。
bash-3.2$ ./eg.sh Run bash script!! Hello, RC!! total 0 drwx------@ 3 codehex staff 96 3 23 21:39 Applications drwx------+ 23 codehex staff 736 4 28 23:20 Desktop drwx------+ 4 codehex staff 128 4 13 11:30 Documents drwx------+ 17 codehex staff 544 4 26 12:53 Downloads drwx------@ 60 codehex staff 1920 4 19 16:11 Library drwx------+ 3 codehex staff 96 3 23 17:37 Movies drwx------+ 4 codehex staff 128 4 19 10:37 Music drwx------+ 3 codehex staff 96 3 23 17:37 Pictures drwxr-xr-x+ 4 codehex staff 128 3 23 17:37 Public lrwxr-xr-x 1 codehex staff 83 4 2 11:05 com.googlecode.iterm2.plist -> /Users/codehex/.ghq/github.com/Code-Hex/dotfiles/iterm2/com.googlecode.iterm2.plist drwxr-xr-x 5 codehex staff 160 4 2 11:54 go Hello, RC!! total 16472 -rw-r--r--@ 1 codehex staff 16260 4 3 20:14 6500104 2.png -rw-r--r--@ 1 codehex staff 6042 4 2 10:34 6500104.png -rw-------@ 1 codehex staff 2676241 4 13 17:30 GoCon.key -rw-------@ 1 codehex staff 818605 4 13 17:30 GoCon.kth -rw-r--r-- 1 codehex staff 15175 4 4 15:52 IHb_9mo8_400x400.jpg -rw-r--r--@ 1 codehex staff 2989022 4 16 17:12 TouchBarEmojis.app.zip drwxr-xr-x@ 8 codehex staff 256 4 26 12:54 alpaca-v0.2.8_20.0 -rw-r--r--@ 1 codehex staff 749660 4 26 12:53 alpaca_20.0.tgz -rw-r--r-- 1 codehex staff 1621 4 9 17:24 cx.txt -rw-r--r-- 1 codehex staff 1086 4 10 17:06 cx2.txt -rw-r--r-- 1 codehex staff 885 4 11 17:59 cx3.txt -rw-r--r-- 1 codehex staff 691 4 12 17:54 cx4.txt drwxr-xr-x 5 codehex staff 160 4 28 23:20 emoji-touchbar -rw-------@ 1 codehex staff 126245 4 13 11:26 image_uploaded_from_ios_1024.png -rw-r--r--@ 1 codehex staff 763 4 3 20:20 memo.txt drwxr-xr-x 13 codehex staff 416 4 25 11:48 screenshots drwxr-xr-x 8 codehex staff 256 4 29 20:15 touchbar-emoji drwxr-xr-x 3 codehex staff 96 4 18 16:25 workspace -rw-r--r--@ 1 codehex staff 368 4 19 17:22 www.google.co.jp:.webloc /Users/codehex/Desktop
source を用いて設定をロードした時のみ反映されるため、本来 bash が持っている cd とは違う動きをする。
このことからチーム内で共有される bash スクリプトに関して考えられることとして次のようなことがあるだろう。
共有されるスクリプト内で source ~/.bashrc
をしてはいけない
チーム内で共有するということは、各々の環境内で全く同じよう(イミュータブル)な動作をしてほしいはずである。 そのため各ユーザーが定義している bashrc をロードするといったことは実行環境によって動作が依存してしまうためやめたほうがいいはず。
環境変数を共有したスクリプト、使っている bash の両方でロードしたい
何かしらインストールして関係ある環境変数を、共有したスクリプトと普段から利用している bash の両方でも扱えるようにしたい場合があるはずである。(今回の場合だとあなたの使っている bash と eg.sh のこと)
その時は次のような解決策が考えられそう。
例えば eg.sh を実行する前に install.sh を実行して、何かをインストールしつつ bashrc に環境変数を書き込んでいき、eg.sh は source ~/.bashrc
を行うというような状況が有り得るかもしれない。
その場合の install.sh は bashrc に環境変数を書き込むのではなく、ホームディレクトリ?等に load_env
とか適当な名前をつけたファイルを作成し、その中に環境変数を書き込むようにしていくほうが良いだろう。
そして bashrc と eg.sh には source ~/load_env
という一行があればどちらも環境変数は読み込めるし、共有されたスクリプトはイミュータブルな動作を保証できるはずである。(ビルトインコマンドを上書きするような設定がロードされないため)
その他
上記は rc ファイルだけではなく profile ファイルにも言える。また、rc や profile を無視して起動するといったオプションもあるとのことなので必要に応じて使えると良さそう。