言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Linux & Mac & Bashコマンド辞典

  1. トップページ
  2. Linux & Mac & Bashコマンド辞典
  3. bashとzshの違い

bashとzshの違い

対応: 全Linux
macOS(2001 Cheetah)
Bash 1.0(1989)

macOS Catalina(2019年)以降、デフォルトシェルが『bash』から『zsh』に変更されました。両者の構文はほぼ同じですが、配列のインデックスやグロブの挙動など、知らずにハマるポイントがあります。このページではスクリプトを書くときに注意すべき違いをまとめます。

主な違い一覧

項目bashzsh
配列の開始インデックス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 始まりです。

users=("user1" "user2" "user3")
echo ${users[0]}
user1
echo ${users[1]}
user2

実行するコマンドは次の通りです。

users=("user1" "user2" "user3")
echo ${users[1]}
user1
echo ${users[2]}
user2

bash ではクォートなしの変数がスペースで自動分割されますが、zsh では分割されません。

msg="hello world"
for word in $msg; do echo "[$word]"; done
[hello]
[world]

実行するコマンドは次の通りです。

msg="hello world"
for word in $msg; do echo "[$word]"; done
[hello world]

再帰グロブ(**)を使ってサブディレクトリのファイルを検索します。bash では事前に『shopt -s globstar』が必要です。

shopt -s globstar
ls **/*.txt

実行するコマンドは次の通りです。

ls **/*.txt

グロブがどのファイルにもマッチしない場合の挙動が異なります。bash はパターン文字列をそのまま渡しますが、zsh はエラーを返します。

ls *.xyz
ls: *.xyz: No such file or directory

実行するコマンドは次の通りです。

ls *.xyz
zsh: no matches found: *.xyz

プロンプトの設定記法が異なります。

bash の場合(~/.bashrc)
PS1='\u@\h:\w\$ '
zsh の場合(~/.zshrc)
PS1='%n@%m:%~%# '
意味bashzsh
ユーザー名\u%n
ホスト名\h%m
カレントディレクトリ\w%~
プロンプト記号(root は #)\$%#

シェルオプションの設定方法が異なります。

shopt -s nocaseglob
shopt -s globstar
shopt -u nocaseglob

実行するコマンドは次の通りです。

setopt no_case_glob
setopt glob_star_short
unsetopt no_case_glob

よくあるミス

よくあるミス1: 配列インデックスの違いに気づかない

bash で書いたスクリプトを zsh で実行すると、配列の最初の要素の取り出し方が変わります。

bash の場合(インデックス 0 が最初)
names=("user1" "user2" "user3")
echo ${names[0]}
user1
zsh の場合(インデックス 0 は空)
names=("user1" "user2" "user3")
echo ${names[0]}

zsh でインデックス 0 を参照しても何も表示されません。最初の要素は ${names[1]} です。移植性を重視する場合はシェバンで bash を明示します。

よくあるミス2: グロブがマッチしないときの挙動の違い

bash ではマッチしないグロブパターンがそのまま文字列として渡されますが、zsh ではエラーになります。

bash の場合(パターン文字列がそのまま渡る)
rm *.xyz
rm: *.xyz: No such file or directory
zsh の場合(エラーになる)
rm *.xyz
zsh: no matches found: *.xyz

zsh では存在しないパターンを渡すとコマンド自体が実行されません。スクリプトの移植時に注意が必要です。

概要

シェルスクリプト(『#!/bin/bash』)として書いたファイルは bash の構文で実行されるため、普段 zsh を使っていてもスクリプトの動作には影響しません。違いが問題になるのはターミナルで直接コマンドを打つ場合や、『~/.bashrc』と『~/.zshrc』の設定を書く場合です。

最も注意すべきは配列の開始インデックスの違いです。bash は 0 始まり、zsh は 1 始まりのため、同じスクリプトでも結果が変わります。

シェバンの使い方は シェバン(shebang)/ chmod +x を、変数の展開については ${パラメータ展開} を、for 文のグロブ活用は for を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。