Ansibleを使ってmacのデフォルトシェルをBash5.0にしてみた
はじめに
Catalina以降macOSのデフォルトシェルはzshになりましたが、私は慣れ親しんだBashを使っています。
プリインストールされた /bin/bash はありますがバージョンが3.2と古く
かつHomebrewで最新版をインストールするのも万一Homebrew不調時にBashごと動作しなくなってしまったら…という不安があり
PCセットアップのたびBash5.0のソースコードをGNU bashのページからダウンロード/パッチ当て/ビルド/インストールした上でデフォルトシェルの変更をしていました。
先日私用PCでmacOSの再インストールを行う機会があり、
せっかくなのでこの作業をAnsible Playbookで自動化してみました。
動作確認環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.6 BuildVersion: 19G73
$ ansible --version ansible 2.9.10 (中略) python version = 3.8.3 (default, May 27 2020, 20:54:22) [Clang 11.0.3 (clang-1103.0.32.59)]
構成
フォルダ構成
最低限ローカル端末で動作させるための環境はこんな感じで
全部で3つのyamlファイルを作成しています。
$ tree . ├── playbook.yml └── roles └── bash ├── tasks │ └── main.yml └── vars └── main.yml
ファイルの中身
playbook.yaml
ローカル端末で今回作成したroleを動かす設定を入れます。
--- - hosts: localhost connection: local gather_facts: no become: no roles: - bash
roles/以下
vars/main.yml はこんな感じ。
patch_versionsで適用するパッチのバージョン一覧を指定していますが、いい感じの書き方がわからずこんなのになってしまいました。スマートな書き方ご存知でしたらぜひ教えてください…!
--- bash_bin: "/usr/local/bin/bash" tmp_dir: "/tmp/bash/" version: 5.0 patch_versions: - "001" - "002" - "003" - "004" - "005" - "006" - "007" - "008" - "009" - "010" - "011" - "012" - "013" - "014" - "015" - "016" - "017" - "018"
tasks/main.yml は以下のような形になりました。
--- # 既存の(非プリインストールの)Bash存在チェック - name: bash existing check stat: path: "{{ bash_bin }}" register: result - block: # 作業用ディレクトリ作成 - name: create tmp dir file: path: "{{ tmp_dir }}" state: directory mode: 0755 # ソースコードのダウンロード・展開 - name: download bash {{ version }} get_url: url: "http://ftp.gnu.org/gnu/bash/bash-{{version}}.tar.gz" dest: "{{ tmp_dir }}/bash-{{version}}.tar.gz" - name: unarchive bash {{ version }} command: cmd: "tar -zxvf {{ tmp_dir }}/bash-{{version}}.tar.gz -C {{ tmp_dir }}/" # パッチ適用 - block: - name: download patches get_url: url: "http://ftp.gnu.org/gnu/bash/bash-{{version}}-patches/bash50-{{ item }}" dest: "{{ tmp_dir }}/bash-{{ version }}" with_items: "{{ patch_versions }}" - name: apply patches patch: src: "{{ tmp_dir }}/bash-{{ version }}/bash50-{{ item }}" basedir: "{{ tmp_dir }}/bash-{{ version }}" with_items: "{{ patch_versions }}" when: patch_versions is defined # インストール - name: configure command: chdir: "{{ tmp_dir }}/bash-{{ version }}" cmd: ./configure - name: make make: chdir: "{{ tmp_dir }}/bash-{{ version }}" - name: make install make: chdir: "{{ tmp_dir }}/bash-{{ version }}" target: install become: yes # /etc/shells編集 - name: edit /etc/shells lineinfile: dest: /etc/shells line: "{{ bash_bin }}" become: yes # デフォルトシェルの変更 - name: chsh command: "chsh -s {{ bash_bin }}" # 作業用ファイル削除 - name: remove tmp dir file: state: absent path: "{{ tmp_dir }}/" when: result.stat.exists == False
ソースコード展開時にはunarchiveモジュールを使いたかったのですが、
unarchiveモジュールはmacにデフォルトで入っているBSD tarではなくGNU tarの存在を前提にしている様子で、私の環境では動作しませんでした。
実行
-Kオプションにより、最初にsudo用のパスワードを要求されます。あと、chsh実行時にもユーザのパスワードが必要です。
ok, changedの数は状況に応じて変わると思います。
Warningも赤裸々に見せちゃうぜ
$ ansible-playbook playbook.yml -K BECOME password: [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [localhost] ********************************************************************************************************************************** TASK [\bash existing check] ************************************************************************************************************************ ok: [localhost] TASK [\bash : create tmp dir] ********************************************************************************************************************** ok: [localhost] TASK [download bash 5.0] ************************************************************************************************************************** ok: [localhost] TASK [unarchive bash 5.0] ************************************************************************************************************************* [WARNING]: Consider using the unarchive module rather than running 'tar'. If you need to use command because unarchive is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [localhost] TASK [\bash : download patches] ******************************************************************************************************************** ok: [localhost] => (item=001) ok: [localhost] => (item=002) ok: [localhost] => (item=003) ok: [localhost] => (item=004) ok: [localhost] => (item=005) ok: [localhost] => (item=006) ok: [localhost] => (item=007) ok: [localhost] => (item=008) ok: [localhost] => (item=009) ok: [localhost] => (item=010) ok: [localhost] => (item=011) ok: [localhost] => (item=012) ok: [localhost] => (item=013) ok: [localhost] => (item=014) ok: [localhost] => (item=015) ok: [localhost] => (item=016) ok: [localhost] => (item=017) ok: [localhost] => (item=018) TASK [\bash : apply patches] *********************************************************************************************************************** changed: [localhost] => (item=001) changed: [localhost] => (item=002) changed: [localhost] => (item=003) changed: [localhost] => (item=004) changed: [localhost] => (item=005) changed: [localhost] => (item=006) changed: [localhost] => (item=007) changed: [localhost] => (item=008) changed: [localhost] => (item=009) changed: [localhost] => (item=010) changed: [localhost] => (item=011) changed: [localhost] => (item=012) changed: [localhost] => (item=013) changed: [localhost] => (item=014) changed: [localhost] => (item=015) changed: [localhost] => (item=016) changed: [localhost] => (item=017) changed: [localhost] => (item=018) TASK [\bash : configure] *************************************************************************************************************************** changed: [localhost] TASK [\bash : make] ******************************************************************************************************************************** changed: [localhost] TASK [\bash : make install] ************************************************************************************************************************ changed: [localhost] TASK [\bash : edit /etc/shells] ******************************************************************************************************************** ok: [localhost] TASK [\bash : chsh] ******************************************************************************************************************************** Password for kato.saori: changed: [localhost] TASK [\bash : remove tmp dir] ********************************************************************************************************************** changed: [localhost] PLAY RECAP **************************************************************************************************************************************** localhost : ok=12 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
シェルを読み込み直すと、パッチ適用された最新のBashが動いてることの確認がとれますぞ!
$ bash --version GNU bash, バージョン 5.0.18(2)-release (x86_64-apple-darwin19.6.0) Copyright (C) 2019 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
おわりに
これで今後のmacのセットアップが楽になるので嬉しいです!