
Ansibleを使ってmacのデフォルトシェルをBash5.0にしてみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
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のセットアップが楽になるので嬉しいです!






