すいません、嘘つきました。Zsh大好きです。
Bashよりも使いやすい(=勘のいい)Zshが憎いです。
はじめに
先日、FishからZshに乗り換えました。
何故かと言うと、FishがPOSIX非互換だったからです。
とは言えども、 ZshもPOSIX非互換 なんですよね。まあ、POSIXモードもあるし、できうる限り対応させようという気がありそうなので、Zshを選びました。
しかし!そうは言ってもやっぱりPOSIX非互換。Bashと共同のスクリプトを使おうとすると、注意しなければならない点 が他のシェルと比べても数多くあります。
この記事では僕が引っかかったところを中心に、備忘録的にそういう点をまとめていきたいと思います。
何かあれば適宜追加していきます。
いいね、ストック等して頂けると今後の勉強の励みになります。
間違いや不足、書いておくと良いのでは?という項目などあればコメントなどでご指摘いただけると助かります。
プロンプトを格納する変数が違う
有名な話ですね。
- Bash
変数PS1
に格納 します。プロンプト用エスケープ文字はバックスラッシュから始まる2文字です。 - Zsh
変数PS1
もしくはPROMPT
に格納 します。エスケープ文字はパーセントから始まる2文字です。
プロンプト表示前に実行するコマンドを、指定する方法が違う
- Bash
変数PROMPT_COMMAND
にコマンドを格納 します。 - Zsh
関数precmd
に実行内容を格納 します。
プロンプトでのANSIエスケープシーケンスの書き方が違う
これはなんでかよくわからない
-
Bash
\[\e[値m\]
と書きます。
普通にecho -e
で使うときは\[\]
は不要です。 -
Zsh
\e[値m
と書きます。 ただ、色指定は%F{色番号}文字%f
と書くほうがいいみたい。
sourceコマンド実行時のスクリプトファイルを指す変数が違う
参考:https://qiita.com/yudoufu/items/48cb6fb71e5b498b2532
例えば、ホームディレクトリで~/dir/script.sh
を読み込む際に、
$ pwd
/home/user
$ source ./dir/script.sh
を実行したときに、script.sh内で自分自身のパスを取得する時に参照する変数を例とします。
- Bash
echo $0 #-bash と返ってくる(失敗)
echo $BASH_SOURCE #~/dir/script.sh と返ってくる(成功)
この場合、echo $(dirname $0)
とすると、~/script.shはありません
って怒られます。(←これが厄介)
- Zsh
echo $0 #~/dir/script.sh と返ってくる(成功)
解決法
echo ${BASH_SOURCE:-$0}
とするといいようです。
シェルスクリプト内の関数内での$0の値が違う
これが意外と厄介だったりする
以下のスクリプトファイルにおいて、
function() {
echo $0
}
- Bash
$ source script.sh #スクリプトファイルの読み込み
$ function
script.sh
- Zsh
% source script.sh #スクリプトファイルの読み込み
% function
function
変数内の一部の文字列を抜き出すときに"最後まで"を指定する方法が違う
これでエラー出た時「だるっ」て思いました。
- Bash
$ HOGE="HOGEHOGE"
$ echo ${HOGE:3:$ }
bash: HOGE: $: 構文エラー: オペランドが予期されます(エラーのある構文は"$")
#エラーになるので、ここは普通に計算しなきゃいけない
$ echo ${HOGE:3:$((${#HOGE} - 3))}
EHOGE
- Zsh
% HOGE="HOGEHOGE"
% echo ${HOGE:3:$ } #なんかこれで上手くいく
EHOGE
チルダ置換が違う
わっかりずら。って思いました。
- Bash
$ whoami
user
$ echo ~
/home/user #チルダがホームディレクトリとして展開
$ echo ~user
/home/user #ホームディレクトリに展開
$ echo ~$USER
~user #変数の場合はホームディレクトリは展開されない
$ echo ~"user"
~user #クオートされていても展開されない
$ echo ~\u\s\e\r
~user #エスケープされてても展開されない
$ echo ~存在しないユーザ
~存在しないユーザ #存在しないユーザの場合そのまま
- Zsh
% whoami
user
% echo ~
/home/user #チルダがホームディレクトリとして展開
% echo ~user
/home/user #ホームディレクトリに展開
% echo ~$USER
/home/user #ホームディレクトリに展開
% echo ~"user"
/home/user #ホームディレクトリに展開
% echo ~\u\s\e\r
/home/user #ホームディレクトリに展開
& echo ~存在しないユーザ
zsh: no such user or named directory: 存在しないユーザ #エラー
配列のインデックス番号が違う
- Bash
$ arr=(hoge fuga piyo)
$ echo arr[1]
fuga #0から順にインデックス
- Zsh
% arr=(hoge fuga piyo)
% echo arr[1]
hoge #1から順にインデックス
おわり
似て非なるところが多すぎて、互換性のあるスクリプトを書くのは難しいですね…
でもFishよりは扱いやすいと思います。Fish、好きなんだけどスクリプトが書けなすぎてねぇ。
Zshに関してはこれも是非是非。(ほぼ個人的備忘録ですが。)
それから、こちらの記事はBashとZshに限らずPOSIX系のシェルに関する互換性の問題をまとめて下さっていますのでこちらもご参考に!