アルパカ三銃士

〜アルパカに酔いしれる獣たちへ捧げる〜

作った bash スクリプトを誰かと共有したい時に気をつけたいこと

以前同期と 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

そして次のような bash スクリプトを用意する。

#!/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 のこと)

その時は次のような解決策が考えられそう。

  • 環境変数を保存するような専用のファイルを作成する
  • そのファイルを bashrc 内で source 経由で読み込めるようにする
  • 同じように共有されたスクリプト内でも読み込めるようにする

例えば eg.sh を実行する前に install.sh を実行して、何かをインストールしつつ bashrc に環境変数を書き込んでいき、eg.sh は source ~/.bashrc を行うというような状況が有り得るかもしれない。

その場合の install.sh は bashrc に環境変数を書き込むのではなく、ホームディレクトリ?等に load_env とか適当な名前をつけたファイルを作成し、その中に環境変数を書き込むようにしていくほうが良いだろう。

そして bashrc と eg.sh には source ~/load_env という一行があればどちらも環境変数は読み込めるし、共有されたスクリプトはイミュータブルな動作を保証できるはずである。(ビルトインコマンドを上書きするような設定がロードされないため)

その他

上記は rc ファイルだけではなく profile ファイルにも言える。また、rc や profile を無視して起動するといったオプションもあるとのことなので必要に応じて使えると良さそう。

takuya-1st.hatenablog.jp