bashとzshの違い
macOS Catalina(2019年)以降、デフォルトシェルが『bash』から『zsh』に変更されました。両者の構文はほぼ同じですが、配列のインデックスやグロブの挙動など、知らずにハマるポイントがあります。このページではスクリプトを書くときに注意すべき違いをまとめます。
主な違い一覧
| 項目 | bash | zsh |
|---|---|---|
| 配列の開始インデックス | 0 始まり | 1 始まり |
| 変数の単語分割 | $var はスペースで自動分割 | $var は分割しない(安全) |
| グロブ(**) | shopt -s globstar が必要 | デフォルトで使える |
| マッチなしグロブ | パターン文字列がそのまま残る | エラーになる(nomatch) |
| プロンプト変数 | \u、\h、\w | %n、%m、%~ |
| オプション設定 | shopt -s オプション名 | setopt オプション名 |
| 設定ファイル | ~/.bashrc | ~/.zshrc |
| 補完システム | bash-completion(外部) | compinit / compsys(組み込み) |
| 右プロンプト | なし | RPROMPT で設定可能 |
| スペル修正 | なし | setopt correct で有効 |
サンプルコード
配列の開始インデックスが異なります。bash は 0 始まり、zsh は 1 始まりです。
bash の場合
fruits=("apple" "banana" "cherry")
echo ${fruits[0]}
apple
echo ${fruits[1]}
banana
zsh の場合
fruits=("apple" "banana" "cherry")
echo ${fruits[1]}
apple
echo ${fruits[2]}
banana
bash ではクォートなしの変数がスペースで自動分割されますが、zsh では分割されません。
bash の場合
msg="hello world" for word in $msg; do echo "[$word]"; done [hello] [world]
zsh の場合
msg="hello world" for word in $msg; do echo "[$word]"; done [hello world]
再帰グロブ(**)を使ってサブディレクトリのファイルを検索します。bash では事前に『shopt -s globstar』が必要です。
bash の場合
shopt -s globstar ls **/*.txt
zsh の場合
ls **/*.txt
グロブがどのファイルにもマッチしない場合の挙動が異なります。bash はパターン文字列をそのまま渡しますが、zsh はエラーを返します。
bash の場合
ls *.xyz ls: *.xyz: No such file or directory
zsh の場合
ls *.xyz zsh: no matches found: *.xyz
プロンプトの設定記法が異なります。
bash の場合(~/.bashrc)
PS1='\u@\h:\w\$ '
zsh の場合(~/.zshrc)
PS1='%n@%m:%~%# '
| 意味 | bash | zsh |
|---|---|---|
| ユーザー名 | \u | %n |
| ホスト名 | \h | %m |
| カレントディレクトリ | \w | %~ |
| プロンプト記号(root は #) | \$ | %# |
シェルオプションの設定方法が異なります。
bash の場合
shopt -s nocaseglob shopt -s globstar shopt -u nocaseglob
zsh の場合
setopt no_case_glob setopt glob_star_short unsetopt no_case_glob
概要
シェルスクリプト(『#!/bin/bash』)として書いたファイルは bash の構文で実行されるため、普段 zsh を使っていてもスクリプトの動作には影響しません。違いが問題になるのはターミナルで直接コマンドを打つ場合や、『~/.bashrc』と『~/.zshrc』の設定を書く場合です。
最も注意すべきは配列の開始インデックスの違いです。bash は 0 始まり、zsh は 1 始まりのため、同じスクリプトでも結果が変わります。移植性を重視するなら『#!/bin/bash』を明記して bash で実行してください。
シェバンの使い方は シェバン(shebang)/ chmod +x を、変数の展開については ${パラメータ展開} を、for 文のグロブ活用は for を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。